Merge pull request #114 from TBMCPlugins/dev

Misc. fixes, chat history config, clickable announcements
This commit is contained in:
Norbi Peti 2020-02-01 20:13:05 +01:00 committed by GitHub
commit c66b212b0c
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
33 changed files with 439 additions and 272 deletions

View file

@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<module org.jetbrains.idea.maven.project.MavenProjectsManager.isMavenModule="true" type="JAVA_MODULE" version="4"> <module org.jetbrains.idea.maven.project.MavenProjectsManager.isMavenModule="true" type="JAVA_MODULE" version="4">
<component name="NewModuleRootManager" LANGUAGE_LEVEL="JDK_13_PREVIEW"> <component name="NewModuleRootManager" LANGUAGE_LEVEL="JDK_11">
<output url="file://$MODULE_DIR$/target/classes" /> <output url="file://$MODULE_DIR$/target/classes" />
<output-test url="file://$MODULE_DIR$/target/test-classes" /> <output-test url="file://$MODULE_DIR$/target/test-classes" />
<content url="file://$MODULE_DIR$"> <content url="file://$MODULE_DIR$">
@ -34,14 +34,14 @@
<orderEntry type="library" scope="PROVIDED" name="Maven: net.ess3:LegacyProvider:2.17.1" level="project" /> <orderEntry type="library" scope="PROVIDED" name="Maven: net.ess3:LegacyProvider:2.17.1" level="project" />
<orderEntry type="library" scope="PROVIDED" name="Maven: net.ess3:ReflectionProvider:2.17.1" level="project" /> <orderEntry type="library" scope="PROVIDED" name="Maven: net.ess3:ReflectionProvider:2.17.1" level="project" />
<orderEntry type="library" scope="PROVIDED" name="Maven: net.ess3:FlattenedProvider:2.17.1" level="project" /> <orderEntry type="library" scope="PROVIDED" name="Maven: net.ess3:FlattenedProvider:2.17.1" level="project" />
<orderEntry type="library" scope="PROVIDED" name="Maven: com.palmergames.bukkit.towny:Towny:0.95.0.0" level="project" /> <orderEntry type="library" scope="PROVIDED" name="Maven: com.palmergames.bukkit.towny:Towny:0.95.2.0" level="project" />
<orderEntry type="library" scope="PROVIDED" name="Maven: com.github.milkbowl:VaultAPI:master-4c248aad62-1" level="project" /> <orderEntry type="library" scope="PROVIDED" name="Maven: com.github.milkbowl:VaultAPI:master-89c00e1cb8-1" level="project" />
<orderEntry type="library" name="Maven: org.bukkit:bukkit:1.13.1-R0.1-SNAPSHOT" level="project" />
<orderEntry type="library" scope="PROVIDED" name="Maven: org.projectlombok:lombok:1.18.10" level="project" /> <orderEntry type="library" scope="PROVIDED" name="Maven: org.projectlombok:lombok:1.18.10" level="project" />
<orderEntry type="library" scope="PROVIDED" name="Maven: org.spigotmc:spigot:1.12.2-R0.1-SNAPSHOT" level="project" /> <orderEntry type="library" scope="PROVIDED" name="Maven: org.spigotmc:spigot:1.12.2-R0.1-SNAPSHOT" level="project" />
<orderEntry type="library" name="Maven: com.github.webbukkit:Dynmap-Towny:master-0.60-g924051d-7" level="project" /> <orderEntry type="library" name="Maven: com.github.webbukkit:Dynmap-Towny:master-0.60-g924051d-7" level="project" />
<orderEntry type="library" name="Maven: com.github.webbukkit:Dynmap:v2.5" level="project" /> <orderEntry type="library" name="Maven: com.github.webbukkit:Dynmap:v2.5" level="project" />
<orderEntry type="library" name="Maven: com.nijikokun.bukkit:Permissions:3.1.6" level="project" /> <orderEntry type="library" name="Maven: com.nijikokun.bukkit:Permissions:3.1.6" level="project" />
<orderEntry type="library" name="Maven: org.bukkit:bukkit:1.7.10-R0.1-SNAPSHOT" level="project" />
<orderEntry type="library" name="Maven: ru.tehkode:PermissionsEx:1.19.1" level="project" /> <orderEntry type="library" name="Maven: ru.tehkode:PermissionsEx:1.19.1" level="project" />
<orderEntry type="library" name="Maven: de.bananaco:bPermissions:2.9.1" level="project" /> <orderEntry type="library" name="Maven: de.bananaco:bPermissions:2.9.1" level="project" />
<orderEntry type="library" name="Maven: com.platymuus.bukkit.permissions:PermissionsBukkit:1.6" level="project" /> <orderEntry type="library" name="Maven: com.platymuus.bukkit.permissions:PermissionsBukkit:1.6" level="project" />

17
pom.xml
View file

@ -135,6 +135,21 @@
<!-- <plugin> <groupId>org.basepom.maven</groupId> <artifactId>duplicate-finder-maven-plugin</artifactId> <!-- <plugin> <groupId>org.basepom.maven</groupId> <artifactId>duplicate-finder-maven-plugin</artifactId>
<version>1.2.1</version> <executions> <execution> <goals> <goal>check</goal> <version>1.2.1</version> <executions> <execution> <goals> <goal>check</goal>
</goals> </execution> </executions> </plugin> --> </goals> </execution> </executions> </plugin> -->
<plugin>
<artifactId>maven-compiler-plugin</artifactId>
<executions>
<execution>
<id>default-testCompile</id>
<goals>
<goal>testCompile</goal>
</goals>
<configuration>
<source>1.8</source>
<target>1.8</target>
</configuration>
</execution>
</executions>
</plugin>
</plugins> </plugins>
</build> </build>
<groupId>buttondevteam</groupId> <groupId>buttondevteam</groupId>
@ -198,7 +213,7 @@
<dependency> <dependency>
<groupId>com.palmergames.bukkit.towny</groupId> <groupId>com.palmergames.bukkit.towny</groupId>
<artifactId>Towny</artifactId> <artifactId>Towny</artifactId>
<version>0.95.0.0</version> <version>0.95.2.0</version>
<scope>provided</scope> <scope>provided</scope>
</dependency> </dependency>
<!-- <dependency> <groupId>au.com.mineauz</groupId> <artifactId>Minigames</artifactId> <!-- <dependency> <groupId>au.com.mineauz</groupId> <artifactId>Minigames</artifactId>

View file

@ -16,7 +16,6 @@ import buttondevteam.chat.components.towncolors.TownColorComponent;
import buttondevteam.chat.components.towny.TownyComponent; import buttondevteam.chat.components.towny.TownyComponent;
import buttondevteam.chat.listener.PlayerJoinLeaveListener; import buttondevteam.chat.listener.PlayerJoinLeaveListener;
import buttondevteam.chat.listener.PlayerListener; import buttondevteam.chat.listener.PlayerListener;
import buttondevteam.core.MainPlugin;
import buttondevteam.core.component.channel.Channel; import buttondevteam.core.component.channel.Channel;
import buttondevteam.lib.TBMCCoreAPI; import buttondevteam.lib.TBMCCoreAPI;
import buttondevteam.lib.architecture.ButtonPlugin; import buttondevteam.lib.architecture.ButtonPlugin;
@ -37,12 +36,12 @@ public class PluginMain extends ButtonPlugin { // Translated to Java: 2015.07.15
public static PluginMain Instance; public static PluginMain Instance;
public static ConsoleCommandSender Console; public static ConsoleCommandSender Console;
public ConfigData<String> notificationSound() { /**
return getIConfig().getData("notificationSound", ""); * If enabled, stores and displays the last 10 messages the player can see (public, their town chat etc.)
} * Can be used with the Discord plugin so players can see some of the conversation they missed that's visible on Discord anyways.
*/
public ConfigData<Float> notificationPitch() { public ConfigData<Boolean> storeChatHistory() {
return getIConfig().getData("notificationPitch", 1.0f); return getIConfig().getData("storeChatHistory", true);
} }
// Fired when plugin is first enabled // Fired when plugin is first enabled

View file

@ -16,14 +16,14 @@ import java.net.URLEncoder;
}) })
public class MWikiCommand extends ICommand2MC { public class MWikiCommand extends ICommand2MC {
@Command2.Subcommand @Command2.Subcommand
public boolean def(CommandSender sender, @Command2.OptionalArg String query) { public boolean def(CommandSender sender, @Command2.OptionalArg @Command2.TextArg String query) {
try { try {
if (query == null) if (query == null)
sender.sendMessage(new String[] { "§bMinecraft Wiki link: http://minecraft.gamepedia.com/", sender.sendMessage(new String[]{"§bMinecraft Wiki link: http://minecraft.gamepedia.com/",
"You can also search on it using /mwiki <query>" }); "You can also search on it using /mwiki <query>"});
else else
sender.sendMessage("§bMinecraft Wiki link: http://minecraft.gamepedia.com/index.php?search=" sender.sendMessage("§bMinecraft Wiki link: http://minecraft.gamepedia.com/index.php?search="
+ URLEncoder.encode(query, "UTF-8") + "&title=Special%3ASearch&go=Go"); + URLEncoder.encode(query, "UTF-8") + "&title=Special%3ASearch&go=Go");
} catch (UnsupportedEncodingException e) { } catch (UnsupportedEncodingException e) {
e.printStackTrace(); e.printStackTrace();
} }

View file

@ -1,14 +1,8 @@
package buttondevteam.chat.commands.ucmds; package buttondevteam.chat.commands.ucmds;
import buttondevteam.chat.PluginMain;
import buttondevteam.lib.chat.Command2; import buttondevteam.lib.chat.Command2;
import buttondevteam.lib.chat.CommandClass; import buttondevteam.lib.chat.CommandClass;
import buttondevteam.lib.chat.TBMCChatAPI;
import buttondevteam.lib.chat.TBMCCommandBase;
import org.bukkit.command.CommandSender; import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player;
import java.util.ArrayList;
@CommandClass(modOnly = false, helpText = { @CommandClass(modOnly = false, helpText = {
"Help", "Help",
@ -36,19 +30,7 @@ public final class HelpCommand extends UCommandBase {
"- Playernames: Hover over them to get some player info", "- Playernames: Hover over them to get some player info",
"-- Respect: This is the number of paid respects divided by eliglble deaths. This is a reference to CoD:AW's \"Press F to pay respects\""}); "-- Respect: This is the number of paid respects divided by eliglble deaths. This is a reference to CoD:AW's \"Press F to pay respects\""});
else if (topicOrCommand.equalsIgnoreCase("commands")) { else if (topicOrCommand.equalsIgnoreCase("commands")) {
ArrayList<String> text = new ArrayList<String>(); sender.sendMessage(getManager().getCommandsText());
text.add("§6---- Command list ----");
for (TBMCCommandBase cmd : TBMCChatAPI.GetCommands().values())
if (!cmd.getClass().getAnnotation(CommandClass.class).modOnly() || PluginMain.permission.has(sender, "tbmc.admin"))
if (!cmd.isPlayerOnly() || sender instanceof Player)
if (!cmd.GetCommandPath().contains(" "))
text.add("/" + cmd.GetCommandPath());
else {
final String topcmd = cmd.GetCommandPath().substring(0, cmd.GetCommandPath().indexOf(' '));
if (!text.contains("/" + topcmd))
text.add("/" + topcmd);
}
sender.sendMessage(text.toArray(new String[0]));
} else if (topicOrCommand.equalsIgnoreCase("colors")) { } else if (topicOrCommand.equalsIgnoreCase("colors")) {
sender.sendMessage(new String[]{"§6---- Chat colors/formats ----", // sender.sendMessage(new String[]{"§6---- Chat colors/formats ----", //
"Tellraw name - Code | Tellraw name - Code", // "Tellraw name - Code | Tellraw name - Code", //

View file

@ -1,5 +1,6 @@
package buttondevteam.chat.commands.ucmds; package buttondevteam.chat.commands.ucmds;
import buttondevteam.chat.PluginMain;
import buttondevteam.core.component.channel.Channel; import buttondevteam.core.component.channel.Channel;
import buttondevteam.lib.chat.ChatMessage; import buttondevteam.lib.chat.ChatMessage;
import buttondevteam.lib.chat.Command2; import buttondevteam.lib.chat.Command2;
@ -21,7 +22,7 @@ public class HistoryCommand extends UCommandBase {
/** /**
* Key: ChannelID_groupID * Key: ChannelID_groupID
*/ */
private static HashMap<String, LinkedList<HistoryEntry>> messages = new HashMap<>(); private static final HashMap<String, LinkedList<HistoryEntry>> messages = new HashMap<>();
@Command2.Subcommand @Command2.Subcommand
public boolean def(CommandSender sender, @Command2.OptionalArg String channel) { public boolean def(CommandSender sender, @Command2.OptionalArg String channel) {
@ -29,6 +30,10 @@ public class HistoryCommand extends UCommandBase {
} }
public static boolean showHistory(CommandSender sender, String channel) { public static boolean showHistory(CommandSender sender, String channel) {
if (!PluginMain.Instance.storeChatHistory().get()) {
sender.sendMessage("§6Chat history is disabled");
return true;
}
Function<Channel, LinkedList<HistoryEntry>> getThem = ch -> messages.get(ch.ID + "_" + ch.getGroupID(sender)); //If can't see, groupID is null, and that shouldn't be in the map Function<Channel, LinkedList<HistoryEntry>> getThem = ch -> messages.get(ch.ID + "_" + ch.getGroupID(sender)); //If can't see, groupID is null, and that shouldn't be in the map
sender.sendMessage("§6---- Chat History ----"); sender.sendMessage("§6---- Chat History ----");
Stream<Channel> stream; Stream<Channel> stream;
@ -43,13 +48,15 @@ public class HistoryCommand extends UCommandBase {
stream = Stream.of(och.get()); stream = Stream.of(och.get());
} }
AtomicBoolean sent = new AtomicBoolean(); AtomicBoolean sent = new AtomicBoolean();
val arr = stream.map(getThem).filter(Objects::nonNull).flatMap(Collection::stream) synchronized (messages) {
val arr = stream.map(getThem).filter(Objects::nonNull).flatMap(Collection::stream)
.sorted(Comparator.comparingLong(he -> he.timestamp)).toArray(HistoryEntry[]::new); .sorted(Comparator.comparingLong(he -> he.timestamp)).toArray(HistoryEntry[]::new);
for (int i = Math.max(0, arr.length - 10); i < arr.length; i++) { for (int i = Math.max(0, arr.length - 10); i < arr.length; i++) {
HistoryEntry e = arr[i]; HistoryEntry e = arr[i];
val cm = e.chatMessage; val cm = e.chatMessage;
sender.sendMessage("[" + e.channel.DisplayName().get() + "] " + cm.getSender().getName() + ": " + cm.getMessage()); sender.sendMessage("[" + e.channel.DisplayName().get() + "] " + cm.getSender().getName() + ": " + cm.getMessage());
sent.set(true); sent.set(true);
}
} }
if (!sent.get()) if (!sent.get())
sender.sendMessage("No messages can be found."); sender.sendMessage("No messages can be found.");
@ -67,11 +74,14 @@ public class HistoryCommand extends UCommandBase {
} }
public static void addChatMessage(ChatMessage chatMessage, Channel channel) { public static void addChatMessage(ChatMessage chatMessage, Channel channel) {
if (!PluginMain.Instance.storeChatHistory().get()) return;
val groupID = channel.getGroupID(chatMessage.getPermCheck()); val groupID = channel.getGroupID(chatMessage.getPermCheck());
if (groupID == null) return; //Just to be sure if (groupID == null) return; //Just to be sure
var ll = messages.computeIfAbsent(channel.ID + "_" + groupID, k -> new LinkedList<>()); //<-- TIL synchronized (messages) {
ll.add(new HistoryEntry(System.nanoTime(), chatMessage, channel)); //Adds as last element var ll = messages.computeIfAbsent(channel.ID + "_" + groupID, k -> new LinkedList<>()); //<-- TIL
while (ll.size() > 10) ll.add(new HistoryEntry(System.nanoTime(), chatMessage, channel)); //Adds as last element
ll.remove(); //Removes the first element while (ll.size() > 10)
ll.remove(); //Removes the first element
}
} }
} }

View file

@ -1,11 +1,13 @@
package buttondevteam.chat.commands.ucmds; package buttondevteam.chat.commands.ucmds;
import buttondevteam.chat.PluginMain;
import buttondevteam.lib.TBMCCoreAPI; import buttondevteam.lib.TBMCCoreAPI;
import buttondevteam.lib.chat.Command2; import buttondevteam.lib.chat.Command2;
import buttondevteam.lib.chat.CommandClass; import buttondevteam.lib.chat.CommandClass;
import buttondevteam.lib.player.ChromaGamerBase.InfoTarget; import buttondevteam.lib.player.ChromaGamerBase.InfoTarget;
import buttondevteam.lib.player.TBMCPlayer; import buttondevteam.lib.player.TBMCPlayer;
import buttondevteam.lib.player.TBMCPlayerBase; import buttondevteam.lib.player.TBMCPlayerBase;
import org.bukkit.Bukkit;
import org.bukkit.command.CommandSender; import org.bukkit.command.CommandSender;
@CommandClass(modOnly = false, helpText = { @CommandClass(modOnly = false, helpText = {
@ -20,16 +22,18 @@ public class InfoCommand extends UCommandBase {
sender.sendMessage("The server console."); sender.sendMessage("The server console.");
return true; return true;
} }
try (TBMCPlayer p = TBMCPlayerBase.getFromName(player, TBMCPlayer.class)) { Bukkit.getScheduler().runTaskAsynchronously(PluginMain.Instance, () -> {
if (p == null) { try (TBMCPlayer p = TBMCPlayerBase.getFromName(player, TBMCPlayer.class)) {
sender.sendMessage("§cThe specified player cannot be found"); if (p == null) {
return true; sender.sendMessage("§cThe specified player cannot be found");
return;
}
sender.sendMessage(p.getInfo(InfoTarget.MCCommand));
} catch (Exception e) {
TBMCCoreAPI.SendException("Error while getting player information!", e);
sender.sendMessage("§cError while getting player information!");
} }
sender.sendMessage(p.getInfo(InfoTarget.MCCommand)); });
} catch (Exception e) {
TBMCCoreAPI.SendException("Error while getting player information!", e);
sender.sendMessage("§cError while getting player information!");
}
return true; return true;
} }
} }

View file

@ -2,9 +2,7 @@ package buttondevteam.chat.commands.ucmds;
import buttondevteam.lib.chat.CommandClass; import buttondevteam.lib.chat.CommandClass;
import buttondevteam.lib.chat.ICommand2MC; import buttondevteam.lib.chat.ICommand2MC;
import buttondevteam.lib.chat.OptionallyPlayerCommandClass;
@CommandClass(modOnly = false, path = "u") @CommandClass(modOnly = false, path = "u")
@OptionallyPlayerCommandClass(playerOnly = false)
public abstract class UCommandBase extends ICommand2MC { public abstract class UCommandBase extends ICommand2MC {
} }

View file

@ -1,15 +1,19 @@
package buttondevteam.chat.components.announce; package buttondevteam.chat.components.announce;
import buttondevteam.chat.commands.ucmds.UCommandBase; import buttondevteam.chat.commands.ucmds.UCommandBase;
import buttondevteam.chat.components.formatter.ChatProcessing;
import buttondevteam.chat.components.formatter.FormatterComponent;
import buttondevteam.chat.components.formatter.formatting.TellrawEvent;
import buttondevteam.chat.components.formatter.formatting.TellrawPart;
import buttondevteam.core.ComponentManager;
import buttondevteam.lib.chat.Command2; import buttondevteam.lib.chat.Command2;
import buttondevteam.lib.chat.CommandClass; import buttondevteam.lib.chat.CommandClass;
import buttondevteam.lib.chat.OptionallyPlayerCommandClass;
import lombok.RequiredArgsConstructor; import lombok.RequiredArgsConstructor;
import lombok.val; import lombok.val;
import org.bukkit.Bukkit;
import org.bukkit.command.CommandSender; import org.bukkit.command.CommandSender;
@CommandClass(modOnly = true) @CommandClass(modOnly = true)
@OptionallyPlayerCommandClass(playerOnly = false)
@RequiredArgsConstructor @RequiredArgsConstructor
public class AnnounceCommand extends UCommandBase { public class AnnounceCommand extends UCommandBase {
private final AnnouncerComponent component; private final AnnouncerComponent component;
@ -28,7 +32,7 @@ public class AnnounceCommand extends UCommandBase {
@Command2.Subcommand(helpText = { @Command2.Subcommand(helpText = {
"Edit announcement", "Edit announcement",
"This command lets you edit an announcement by its index.", "This command lets you edit an announcement by its index.",
"Shouldn't be used directly, use either command blocks or click on an announcement in /u announce list (WIP) instead." //TODO: <-- "Shouldn't be used directly, use either command blocks or click on an announcement in /u announce list instead."
}) })
public boolean edit(CommandSender sender, byte index, @Command2.TextArg String text) { public boolean edit(CommandSender sender, byte index, @Command2.TextArg String text) {
String finalmessage1 = text.replace('&', '§'); String finalmessage1 = text.replace('&', '§');
@ -49,8 +53,19 @@ public class AnnounceCommand extends UCommandBase {
sender.sendMessage("§bList of announce messages:§r"); sender.sendMessage("§bList of announce messages:§r");
sender.sendMessage("§bFormat: [index] message§r"); sender.sendMessage("§bFormat: [index] message§r");
int i = 0; int i = 0;
for (String message : component.announceMessages().get()) for (String message : component.announceMessages().get()) {
sender.sendMessage("[" + i++ + "] " + message); String msg = "[" + i++ + "] " + message;
//noinspection SuspiciousMethodCalls
if (!ComponentManager.isEnabled(FormatterComponent.class) || !Bukkit.getOnlinePlayers().contains(sender)) {
sender.sendMessage(msg);
continue;
}
String json = ChatProcessing.toJson(new TellrawPart(msg)
.setHoverEvent(TellrawEvent.create(TellrawEvent.HoverAction.SHOW_TEXT, "Click to edit"))
.setClickEvent(TellrawEvent.create(TellrawEvent.ClickAction.SUGGEST_COMMAND,
"/" + getCommandPath() + " edit " + (i - 1) + " " + message.replace('§', '&'))));
Bukkit.dispatchCommand(Bukkit.getConsoleSender(), "tellraw " + sender.getName() + " " + json);
}
sender.sendMessage("§bCurrent wait time between announcements: " sender.sendMessage("§bCurrent wait time between announcements: "
+ component.announceTime().get() / 60 / 1000 + " minute(s)§r"); + component.announceTime().get() / 60 / 1000 + " minute(s)§r");
return true; return true;

View file

@ -5,23 +5,31 @@ import buttondevteam.core.component.channel.Channel;
import buttondevteam.lib.TBMCSystemChatEvent; import buttondevteam.lib.TBMCSystemChatEvent;
import buttondevteam.lib.architecture.Component; import buttondevteam.lib.architecture.Component;
import buttondevteam.lib.architecture.ConfigData; import buttondevteam.lib.architecture.ConfigData;
import buttondevteam.lib.architecture.ListConfigData;
import buttondevteam.lib.chat.TBMCChatAPI; import buttondevteam.lib.chat.TBMCChatAPI;
import org.bukkit.Bukkit; import org.bukkit.Bukkit;
import java.util.ArrayList; /**
* Displays the configured messages at the set interval when someone is online.
*/
public class AnnouncerComponent extends Component<PluginMain> implements Runnable { public class AnnouncerComponent extends Component<PluginMain> implements Runnable {
public ConfigData<ArrayList<String>> announceMessages() { /**
return getConfig().getData("announceMessages", new ArrayList<>(0)); * The messages to display to players.
*/
public ListConfigData<String> announceMessages() {
return getConfig().getListData("announceMessages");
} }
/**
* The time in milliseconds between the messages. Use /u announce settime to set minutes.
*/
public ConfigData<Integer> announceTime() { public ConfigData<Integer> announceTime() {
return getConfig().getData("announceTime", 15 * 60 * 1000); return getConfig().getData("announceTime", 15 * 60 * 1000);
} }
private TBMCSystemChatEvent.BroadcastTarget target; private TBMCSystemChatEvent.BroadcastTarget target;
private static int AnnounceMessageIndex = 0; private int AnnounceMessageIndex = 0;
@Override @Override
public void run() { public void run() {
@ -43,7 +51,7 @@ public class AnnouncerComponent extends Component<PluginMain> implements Runnabl
@Override @Override
protected void enable() { protected void enable() {
target= TBMCSystemChatEvent.BroadcastTarget.add("announcements"); target = TBMCSystemChatEvent.BroadcastTarget.add("announcements");
registerCommand(new AnnounceCommand(this)); registerCommand(new AnnounceCommand(this));
new Thread(this).start(); new Thread(this).start();
} }

View file

@ -15,8 +15,12 @@ import java.util.Map;
import java.util.NoSuchElementException; import java.util.NoSuchElementException;
import java.util.function.Consumer; import java.util.function.Consumer;
/**
* Allows players to append tableflips and other things to their messages. Everything is configurable here.
*/
public class AppendTextComponent extends Component<PluginMain> { public class AppendTextComponent extends Component<PluginMain> {
private Map<String, IHaveConfig> appendTexts; private Map<String, IHaveConfig> appendTexts;
private ConfigData<String[]> helpText(IHaveConfig config) { private ConfigData<String[]> helpText(IHaveConfig config) {
return config.getData("helpText", () -> new String[]{ return config.getData("helpText", () -> new String[]{
"Tableflip", // "Tableflip", //

View file

@ -5,6 +5,7 @@ import buttondevteam.chat.components.formatter.formatting.TellrawEvent;
import buttondevteam.chat.components.formatter.formatting.TellrawPart; import buttondevteam.chat.components.formatter.formatting.TellrawPart;
import buttondevteam.core.ComponentManager; import buttondevteam.core.ComponentManager;
import buttondevteam.lib.architecture.Component; import buttondevteam.lib.architecture.Component;
import buttondevteam.lib.architecture.ComponentMetadata;
import buttondevteam.lib.player.TBMCPlayer; import buttondevteam.lib.player.TBMCPlayer;
import buttondevteam.lib.player.TBMCPlayerJoinEvent; import buttondevteam.lib.player.TBMCPlayerJoinEvent;
import lombok.val; import lombok.val;
@ -15,6 +16,10 @@ import org.bukkit.event.Listener;
import org.bukkit.event.player.PlayerMoveEvent; import org.bukkit.event.player.PlayerMoveEvent;
import org.bukkit.event.player.PlayerTeleportEvent; import org.bukkit.event.player.PlayerTeleportEvent;
/**
* Allows players to enter chat-only mode which puts them into spectator mode and disallows everything besides chatting.
*/
@ComponentMetadata(enabledByDefault = false)
public class ChatOnlyComponent extends Component implements Listener { public class ChatOnlyComponent extends Component implements Listener {
@Override @Override
protected void enable() { protected void enable() {

View file

@ -1,13 +1,11 @@
package buttondevteam.chat.components.chatonly; package buttondevteam.chat.components.chatonly;
import buttondevteam.lib.chat.ICommand2MC;
import org.bukkit.GameMode;
import org.bukkit.entity.Player;
import buttondevteam.chat.ChatPlayer; import buttondevteam.chat.ChatPlayer;
import buttondevteam.lib.chat.CommandClass; import buttondevteam.lib.chat.CommandClass;
import buttondevteam.lib.chat.PlayerCommandBase; import buttondevteam.lib.chat.ICommand2MC;
import buttondevteam.lib.player.TBMCPlayer; import buttondevteam.lib.player.TBMCPlayer;
import org.bukkit.GameMode;
import org.bukkit.entity.Player;
@CommandClass(modOnly = false, helpText = { @CommandClass(modOnly = false, helpText = {
"§6---- Chat-only mode ----", // "§6---- Chat-only mode ----", //

View file

@ -6,10 +6,8 @@ import buttondevteam.chat.commands.ucmds.UCommandBase;
import buttondevteam.lib.TBMCCoreAPI; import buttondevteam.lib.TBMCCoreAPI;
import buttondevteam.lib.chat.Command2; import buttondevteam.lib.chat.Command2;
import buttondevteam.lib.chat.CommandClass; import buttondevteam.lib.chat.CommandClass;
import buttondevteam.lib.chat.OptionallyPlayerCommandClass;
import buttondevteam.lib.player.TBMCPlayer; import buttondevteam.lib.player.TBMCPlayer;
import lombok.RequiredArgsConstructor; import lombok.RequiredArgsConstructor;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player; import org.bukkit.entity.Player;
import java.util.Timer; import java.util.Timer;
@ -19,14 +17,12 @@ import java.util.Timer;
"Accepts a flair from Reddit", // "Accepts a flair from Reddit", //
"Use /u accept <username> if you commented from multiple accounts" "Use /u accept <username> if you commented from multiple accounts"
}) })
@OptionallyPlayerCommandClass(playerOnly = true)
@RequiredArgsConstructor @RequiredArgsConstructor
public class AcceptCommand extends UCommandBase { public class AcceptCommand extends UCommandBase {
private final FlairComponent component; private final FlairComponent component;
@Command2.Subcommand @Command2.Subcommand
public boolean def(CommandSender sender, @Command2.OptionalArg String username) { public boolean def(Player player, @Command2.OptionalArg String username) {
final Player player = (Player) sender;
ChatPlayer p = TBMCPlayer.getPlayer(player.getUniqueId(), ChatPlayer.class); ChatPlayer p = TBMCPlayer.getPlayer(player.getUniqueId(), ChatPlayer.class);
if (username == null && p.UserNames().size() > 1) { if (username == null && p.UserNames().size() > 1) {
player.sendMessage("§9Multiple users commented your name. §bPlease pick one using /u accept <username>"); player.sendMessage("§9Multiple users commented your name. §bPlease pick one using /u accept <username>");

View file

@ -4,6 +4,7 @@ import buttondevteam.chat.ChatPlayer;
import buttondevteam.chat.PluginMain; import buttondevteam.chat.PluginMain;
import buttondevteam.lib.TBMCCoreAPI; import buttondevteam.lib.TBMCCoreAPI;
import buttondevteam.lib.architecture.Component; import buttondevteam.lib.architecture.Component;
import buttondevteam.lib.architecture.ComponentMetadata;
import buttondevteam.lib.architecture.ConfigData; import buttondevteam.lib.architecture.ConfigData;
import buttondevteam.lib.player.TBMCPlayerBase; import buttondevteam.lib.player.TBMCPlayerBase;
import com.google.gson.JsonArray; import com.google.gson.JsonArray;
@ -22,9 +23,17 @@ import java.net.UnknownHostException;
import java.text.SimpleDateFormat; import java.text.SimpleDateFormat;
import java.util.*; import java.util.*;
/**
* This component checks a specific Reddit thread every 10 seconds for comments such as "IGN: NorbiPeti" to link Reddit accounts and to determine their /r/thebutton flair.
* This was the original goal of this plugin when it was made.
*/
@ComponentMetadata(enabledByDefault = false)
public class FlairComponent extends Component<PluginMain> { public class FlairComponent extends Component<PluginMain> {
/**
* The Reddit thread to check for account connections. Re-enable the component if this was empty.
*/
ConfigData<String> flairThreadURL() { ConfigData<String> flairThreadURL() {
return getConfig().getData("flairThreadURL", "https://www.reddit.com/r/Chromagamers/comments/51ys94/flair_thread_for_the_mc_server/"); return getConfig().getData("flairThreadURL", "");
} }
/** /**
@ -52,7 +61,7 @@ public class FlairComponent extends Component<PluginMain> {
private void FlairGetterThreadMethod() { private void FlairGetterThreadMethod() {
int errorcount = 0; int errorcount = 0;
while (isEnabled()) { while (isEnabled() && flairThreadURL().get().length() > 0) {
try { try {
String body = TBMCCoreAPI.DownloadString(flairThreadURL().get() + ".json?limit=1000"); String body = TBMCCoreAPI.DownloadString(flairThreadURL().get() + ".json?limit=1000");
JsonArray json = new JsonParser().parse(body).getAsJsonArray().get(1).getAsJsonObject().get("data") JsonArray json = new JsonParser().parse(body).getAsJsonArray().get(1).getAsJsonObject().get("data")

View file

@ -4,20 +4,16 @@ import buttondevteam.chat.ChatPlayer;
import buttondevteam.chat.commands.ucmds.UCommandBase; import buttondevteam.chat.commands.ucmds.UCommandBase;
import buttondevteam.lib.chat.Command2; import buttondevteam.lib.chat.Command2;
import buttondevteam.lib.chat.CommandClass; import buttondevteam.lib.chat.CommandClass;
import buttondevteam.lib.chat.OptionallyPlayerCommandClass;
import buttondevteam.lib.player.TBMCPlayer; import buttondevteam.lib.player.TBMCPlayer;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player; import org.bukkit.entity.Player;
@CommandClass(modOnly = false, helpText = { @CommandClass(modOnly = false, helpText = {
"Ignore flair", "Ignore flair",
"Stop the \"write your name in the thread\" message from showing up" "Stop the \"write your name in the thread\" message from showing up"
}) })
@OptionallyPlayerCommandClass(playerOnly = true)
public final class IgnoreCommand extends UCommandBase { public final class IgnoreCommand extends UCommandBase {
@Command2.Subcommand @Command2.Subcommand
public boolean def(CommandSender sender) { public boolean def(Player player) {
final Player player = (Player) sender;
ChatPlayer p = TBMCPlayer.getPlayer(player.getUniqueId(), ChatPlayer.class); ChatPlayer p = TBMCPlayer.getPlayer(player.getUniqueId(), ChatPlayer.class);
if (p.FlairState().get().equals(FlairStates.Accepted)) { if (p.FlairState().get().equals(FlairStates.Accepted)) {
player.sendMessage("§cYou can only ignore the \"write your name in the thread\" message."); player.sendMessage("§cYou can only ignore the \"write your name in the thread\" message.");

View file

@ -25,6 +25,7 @@ import buttondevteam.lib.player.ChromaGamerBase;
import buttondevteam.lib.player.TBMCPlayer; import buttondevteam.lib.player.TBMCPlayer;
import buttondevteam.lib.player.TBMCPlayerBase; import buttondevteam.lib.player.TBMCPlayerBase;
import com.earth2me.essentials.User; import com.earth2me.essentials.User;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.Lists; import com.google.common.collect.Lists;
import com.google.gson.Gson; import com.google.gson.Gson;
import com.google.gson.GsonBuilder; import com.google.gson.GsonBuilder;
@ -49,12 +50,13 @@ public class ChatProcessing {
private static final Pattern HASHTAG_PATTERN = Pattern.compile("#(\\w+)"); private static final Pattern HASHTAG_PATTERN = Pattern.compile("#(\\w+)");
private static final Pattern URL_PATTERN = Pattern.compile("(http[\\w:/?=$\\-_.+!*'(),&]+(?:#[\\w]+)?)"); private static final Pattern URL_PATTERN = Pattern.compile("(http[\\w:/?=$\\-_.+!*'(),&]+(?:#[\\w]+)?)");
public static final Pattern ENTIRE_MESSAGE_PATTERN = Pattern.compile(".+"); public static final Pattern ENTIRE_MESSAGE_PATTERN = Pattern.compile(".+");
private static final Pattern UNDERLINED_PATTERN = Pattern.compile("_"); private static final Pattern UNDERLINED_PATTERN = Pattern.compile("__");
private static final Pattern ITALIC_PATTERN = Pattern.compile("\\*"); private static final Pattern ITALIC_PATTERN = Pattern.compile("\\*");
private static final Pattern ITALIC_PATTERN_2 = Pattern.compile("_");
private static final Pattern BOLD_PATTERN = Pattern.compile("\\*\\*"); private static final Pattern BOLD_PATTERN = Pattern.compile("\\*\\*");
private static final Pattern CODE_PATTERN = Pattern.compile("`"); private static final Pattern CODE_PATTERN = Pattern.compile("`");
private static final Pattern MASKED_LINK_PATTERN = Pattern.compile("\\[([^\\[\\]]+)]\\(([^()]+)\\)"); private static final Pattern MASKED_LINK_PATTERN = Pattern.compile("\\[([^\\[\\]]+)]\\(([^()]+)\\)");
private static final Pattern SOMEONE_PATTERN = Pattern.compile("@someone"); //TODO private static final Pattern SOMEONE_PATTERN = Pattern.compile("@someone");
private static final Pattern STRIKETHROUGH_PATTERN = Pattern.compile("~~"); private static final Pattern STRIKETHROUGH_PATTERN = Pattern.compile("~~");
private static final Pattern SPOILER_PATTERN = Pattern.compile("\\|\\|"); private static final Pattern SPOILER_PATTERN = Pattern.compile("\\|\\|");
private static final Color[] RainbowPresserColors = new Color[]{Color.Red, Color.Gold, Color.Yellow, Color.Green, private static final Color[] RainbowPresserColors = new Color[]{Color.Red, Color.Gold, Color.Yellow, Color.Green,
@ -68,7 +70,8 @@ public class ChatProcessing {
ChatFormatter.builder("bold", BOLD_PATTERN).bold(true).removeCharCount((short) 2).type(ChatFormatter.Type.Range) ChatFormatter.builder("bold", BOLD_PATTERN).bold(true).removeCharCount((short) 2).type(ChatFormatter.Type.Range)
.priority(Priority.High).build(), .priority(Priority.High).build(),
ChatFormatter.builder("italic", ITALIC_PATTERN).italic(true).removeCharCount((short) 1).type(ChatFormatter.Type.Range).build(), ChatFormatter.builder("italic", ITALIC_PATTERN).italic(true).removeCharCount((short) 1).type(ChatFormatter.Type.Range).build(),
ChatFormatter.builder("underlined", UNDERLINED_PATTERN).underlined(true).removeCharCount((short) 1).type(ChatFormatter.Type.Range) ChatFormatter.builder("italic2", ITALIC_PATTERN_2).italic(true).removeCharCount((short) 1).type(ChatFormatter.Type.Range).build(),
ChatFormatter.builder("underlined", UNDERLINED_PATTERN).underlined(true).removeCharCount((short) 2).type(ChatFormatter.Type.Range)
.build(), .build(),
ChatFormatter.builder("strikethrough", STRIKETHROUGH_PATTERN).strikethrough(true).removeCharCount((short) 2).type(ChatFormatter.Type.Range) ChatFormatter.builder("strikethrough", STRIKETHROUGH_PATTERN).strikethrough(true).removeCharCount((short) 2).type(ChatFormatter.Type.Range)
.build(), .build(),
@ -98,7 +101,15 @@ public class ChatProcessing {
builder.setOpenlink(link); builder.setOpenlink(link);
return text; return text;
}).type(ChatFormatter.Type.Excluder).build(), }).type(ChatFormatter.Type.Excluder).build(),
ChatFormatter.builder("url", URL_PATTERN).underlined(true).openlink("$1").type(ChatFormatter.Type.Excluder).build()); ChatFormatter.builder("url", URL_PATTERN).underlined(true).openlink("$1").type(ChatFormatter.Type.Excluder).build(),
ChatFormatter.builder("someone", SOMEONE_PATTERN).color(Color.Aqua).onmatch((match, builder, section) -> {
if (Bukkit.getOnlinePlayers().size() == 0) return match;
var players = ImmutableList.copyOf(Bukkit.getOnlinePlayers());
var playerC = new Random().nextInt(players.size());
var player = players.get(playerC);
playPingSound(player, ComponentManager.getIfEnabled(FormatterComponent.class));
return "@someone (" + player.getDisplayName() + "§r)";
}).build());
private static Gson gson = new GsonBuilder() private static Gson gson = new GsonBuilder()
.registerTypeHierarchyAdapter(TellrawSerializableEnum.class, new TellrawSerializer.TwEnum()) .registerTypeHierarchyAdapter(TellrawSerializableEnum.class, new TellrawSerializer.TwEnum())
.registerTypeHierarchyAdapter(Collection.class, new TellrawSerializer.TwCollection()) .registerTypeHierarchyAdapter(Collection.class, new TellrawSerializer.TwCollection())
@ -146,13 +157,9 @@ public class ChatProcessing {
ArrayList<ChatFormatter> formatters; ArrayList<ChatFormatter> formatters;
if (component.allowFormatting().get()) { if (component.allowFormatting().get()) {
formatters = addFormatters(colormode, e::shouldSendTo); formatters = addFormatters(colormode, e::shouldSendTo, component);
if (colormode == channel.Color().get() && mp != null && mp.RainbowPresserColorMode) { // Only overwrite channel color if (colormode == channel.Color().get() && mp != null && mp.RainbowPresserColorMode) { // Only overwrite channel color
final AtomicInteger rpc = new AtomicInteger(0); createRPC(colormode, formatters);
formatters.add(ChatFormatter.builder("word", WORD_PATTERN).color(colormode).onmatch((match, cf, s) -> {
cf.setColor(RainbowPresserColors[rpc.getAndUpdate(i -> ++i < RainbowPresserColors.length ? i : 0)]);
return match;
}).build());
} }
pingedconsole = false; // Will set it to true onmatch (static constructor) pingedconsole = false; // Will set it to true onmatch (static constructor)
} else } else
@ -206,13 +213,21 @@ public class ChatProcessing {
return false; return false;
} }
static String toJson(TellrawPart json) { static void createRPC(Color colormode, ArrayList<ChatFormatter> formatters) {
final AtomicInteger rpc = new AtomicInteger(0);
formatters.add(ChatFormatter.builder("rpc", WORD_PATTERN).color(colormode).onmatch((match, cf, s) -> {
cf.setColor(RainbowPresserColors[rpc.getAndUpdate(i -> ++i < RainbowPresserColors.length ? i : 0)]);
return match;
}).build());
}
public static String toJson(TellrawPart json) {
return gson.toJson(json); return gson.toJson(json);
} }
static TellrawPart createTellraw(CommandSender sender, String message, @Nullable Player player, static TellrawPart createTellraw(CommandSender sender, String message, @Nullable Player player,
@Nullable ChatPlayer mp, @Nullable ChromaGamerBase cg, final String channelidentifier, @Nullable ChatPlayer mp, @Nullable ChromaGamerBase cg, final String channelidentifier,
String origin) { String origin) {
TellrawPart json = new TellrawPart(""); TellrawPart json = new TellrawPart("");
ChatOnlyComponent.tellrawCreate(mp, json); //TODO: Make nice API ChatOnlyComponent.tellrawCreate(mp, json); //TODO: Make nice API
json.addExtra( json.addExtra(
@ -249,7 +264,7 @@ public class ChatProcessing {
+ "]"; + "]";
} }
static ArrayList<ChatFormatter> addFormatters(Color colormode, Predicate<Player> canSee) { static ArrayList<ChatFormatter> addFormatters(Color colormode, Predicate<Player> canSee, @Nullable FormatterComponent component) {
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
ArrayList<ChatFormatter> formatters = (ArrayList<ChatFormatter>) commonFormatters.clone(); ArrayList<ChatFormatter> formatters = (ArrayList<ChatFormatter>) commonFormatters.clone();
@ -306,7 +321,7 @@ public class ChatProcessing {
} }
ChatPlayer mpp = TBMCPlayer.getPlayer(nottest ? p.getUniqueId() : new UUID(0, 0), ChatPlayer.class); ChatPlayer mpp = TBMCPlayer.getPlayer(nottest ? p.getUniqueId() : new UUID(0, 0), ChatPlayer.class);
if (nottest) { if (nottest) {
playPingSound(p); playPingSound(p, component);
} }
String color = String.format("§%x", (mpp.GetFlairColor() == 0x00 ? 0xb : mpp.GetFlairColor())); String color = String.format("§%x", (mpp.GetFlairColor() == 0x00 ? 0xb : mpp.GetFlairColor()));
return color + (nottest ? p.getName() : pn.get()) + "§r"; //Fix name casing, except when testing return color + (nottest ? p.getName() : pn.get()) + "§r"; //Fix name casing, except when testing
@ -322,7 +337,7 @@ public class ChatProcessing {
+ match.toLowerCase() + " but was reported as online."); + match.toLowerCase() + " but was reported as online.");
return "§c" + match + "§r"; return "§c" + match + "§r";
} }
playPingSound(p); playPingSound(p, component);
return PluginMain.essentials.getUser(p).getNickname(); return PluginMain.essentials.getUser(p).getNickname();
} }
error.accept("Player nicknamed " + match.toLowerCase() error.accept("Player nicknamed " + match.toLowerCase()
@ -333,12 +348,12 @@ public class ChatProcessing {
return formatters; return formatters;
} }
private static void playPingSound(Player p) { private static void playPingSound(Player p, @Nullable FormatterComponent component) {
if (PluginMain.Instance.notificationSound().get().length() == 0) if (component == null || component.notificationSound().get().length() == 0)
p.playSound(p.getLocation(), Sound.ENTITY_ARROW_HIT_PLAYER, 1.0f, 0.5f); // TODO: Airhorn p.playSound(p.getLocation(), Sound.ENTITY_ARROW_HIT_PLAYER, 1.0f, 0.5f); // TODO: Airhorn
else else
p.playSound(p.getLocation(), PluginMain.Instance.notificationSound().get(), 1.0f, p.playSound(p.getLocation(), component.notificationSound().get(), 1.0f,
PluginMain.Instance.notificationPitch().get()); component.notificationPitch().get());
} }
static void doFunStuff(CommandSender sender, TBMCChatEventBase event, String message) { static void doFunStuff(CommandSender sender, TBMCChatEventBase event, String message) {

View file

@ -8,14 +8,33 @@ import buttondevteam.lib.architecture.Component;
import buttondevteam.lib.architecture.ConfigData; import buttondevteam.lib.architecture.ConfigData;
/** /**
* This component handles the custom processing of chat messages. If this component is disabled channels won't be supported either in Minecraft. * This component handles the custom processing of chat messages. If this component is disabled channels won't be supported in Minecraft.
* If you only want to disable the formatting features, set allowFormatting to false. * If you only want to disable the formatting features, set allowFormatting to false.
* If you're using another chat plugin, you should disable the whole component.
*/ */
public class FormatterComponent extends Component<PluginMain> { public class FormatterComponent extends Component<PluginMain> {
/**
* Determines whether Markdown formatting, name mentioning and similar features are enabled.
*/
ConfigData<Boolean> allowFormatting() { ConfigData<Boolean> allowFormatting() {
return getConfig().getData("allowFormatting", true); return getConfig().getData("allowFormatting", true);
} }
/**
* The sound to play when a player is mentioned. Leave empty to use default.
*/
public ConfigData<String> notificationSound() {
return getConfig().getData("notificationSound", "");
}
/**
* The pitch of the notification sound.
*/
public ConfigData<Float> notificationPitch() {
return getConfig().getData("notificationPitch", 1.0f);
}
@Override @Override
protected void enable() { protected void enable() {
MainPlugin.Instance.setChatHandlerEnabled(false); //Disable Core chat handler - if this component is disabled then let it do it's job MainPlugin.Instance.setChatHandlerEnabled(false); //Disable Core chat handler - if this component is disabled then let it do it's job

View file

@ -45,6 +45,13 @@ public final class ChatFormatter {
String hoverText; String hoverText;
String name; String name;
@Override
public String toString() {
return "ChatFormatter{" +
"name='" + name + '\'' +
'}';
}
public static ChatFormatterBuilder builder(String name, Pattern regex) { public static ChatFormatterBuilder builder(String name, Pattern regex) {
return builder().regex(regex).name(name); return builder().regex(regex).name(name);
} }
@ -98,7 +105,7 @@ public final class ChatFormatter {
sections = convertRangeSections(str, sections, remchars); sections = convertRangeSections(str, sections, remchars);
header("Adding remove chars (RC)"); // Important to add after the range section conversion header("Adding remove chars (RC)"); // Important to add after the range section conversion
addRemChars(sections, remchars); addRemChars(sections, remchars, str);
header("Section combining"); header("Section combining");
combineSections(str, sections); combineSections(str, sections);
@ -134,12 +141,26 @@ public final class ChatFormatter {
} }
} }
private static void newCombine(String str, ArrayList<FormattedSection> sections, ArrayList<int[]> remchars) {
var stack = new Stack<FormattedSection>();
for (int i = 0; i < str.length(); i++) {
for (Iterator<FormattedSection> iterator = sections.iterator(); iterator.hasNext(); ) {
FormattedSection section = iterator.next();
if (section.Start <= i) {
stack.push(section);
iterator.remove();
}
}
}
}
private static ArrayList<FormattedSection> convertRangeSections(String str, ArrayList<FormattedSection> sections, ArrayList<int[]> remchars) { private static ArrayList<FormattedSection> convertRangeSections(String str, ArrayList<FormattedSection> sections, ArrayList<int[]> remchars) {
ArrayList<FormattedSection> combined = new ArrayList<>(); ArrayList<FormattedSection> combined = new ArrayList<>();
Map<ChatFormatter, FormattedSection> nextSection = new HashMap<>(); Map<ChatFormatter, FormattedSection> nextSection = new HashMap<>();
boolean escaped = false; boolean escaped = false;
int takenStart = -1, takenEnd = -1; int takenStart = -1, takenEnd = -1;
ChatFormatter takenFormatter = null; ChatFormatter takenFormatter = null;
boolean takenByBigGuy = false; //Can't win against him (finished sections take precedence)
for (final FormattedSection section : sections) { for (final FormattedSection section : sections) {
// Set ending to -1 until closed with another 1 long "section" - only do this if IsRange is true // Set ending to -1 until closed with another 1 long "section" - only do this if IsRange is true
if (section.type != Type.Range) { if (section.type != Type.Range) {
@ -155,11 +176,12 @@ public final class ChatFormatter {
continue; continue;
} }
if (!escaped) { if (!escaped) {
ChatFormatter formatter = section.Formatters.get(0);
if (section.Start == takenStart || (section.Start > takenStart && section.Start < takenEnd)) { if (section.Start == takenStart || (section.Start > takenStart && section.Start < takenEnd)) {
/* /*
* if (nextSection.containsKey(section.Formatters.get(0)) ? section.RemCharFromStart <= takenEnd - takenStart : section.RemCharFromStart > takenEnd - takenStart) { * if (nextSection.containsKey(section.Formatters.get(0)) ? section.RemCharFromStart <= takenEnd - takenStart : section.RemCharFromStart > takenEnd - takenStart) {
*/ */
if (section.Formatters.get(0).removeCharCount < takenEnd - takenStart) { if (takenByBigGuy || formatter.removeCharCount < takenEnd - takenStart) {
DebugCommand.SendDebugMessage("Lose: " + section); DebugCommand.SendDebugMessage("Lose: " + section);
sendMessageWithPointer(str, section.Start, section.End); sendMessageWithPointer(str, section.Start, section.End);
DebugCommand.SendDebugMessage("And win: " + takenFormatter); DebugCommand.SendDebugMessage("And win: " + takenFormatter);
@ -170,21 +192,38 @@ public final class ChatFormatter {
sendMessageWithPointer(str, section.Start, section.End); sendMessageWithPointer(str, section.Start, section.End);
DebugCommand.SendDebugMessage("And lose: " + takenFormatter); DebugCommand.SendDebugMessage("And lose: " + takenFormatter);
} }
boolean hasFormatter = nextSection.containsKey(formatter);
if (!hasFormatter) {
val ff = formatter;
val cfo = nextSection.keySet().stream().filter(f -> f.removeCharCount > ff.removeCharCount).findAny();
if (cfo.isPresent()) {
//formatter = cfo.get();
val s = nextSection.get(cfo.get());
int takenS = section.Start, takenE = section.Start + formatter.removeCharCount;
if (s.Start == takenS || (s.Start > takenS && s.Start < takenE)) { //Peek()
hasFormatter = true;
continue; //Not the formatter we're looking for - TODO: It doesn't fix the problem of italics at the end
}
}
}
takenStart = section.Start; takenStart = section.Start;
takenEnd = section.Start + section.Formatters.get(0).removeCharCount; takenEnd = section.Start + formatter.removeCharCount;
takenFormatter = section.Formatters.get(0); takenFormatter = formatter;
if (nextSection.containsKey(section.Formatters.get(0))) { if (hasFormatter) {
FormattedSection s = nextSection.remove(section.Formatters.get(0)); FormattedSection s = nextSection.remove(formatter);
//HACK? If we can find another section that removes more characters, finish that instead
// section: the ending marker section - s: the to-be full section // section: the ending marker section - s: the to-be full section
s.End = takenEnd - 1; //Take the remCharCount into account as well s.End = takenEnd - 1; //Take the remCharCount into account as well
// s.IsRange = false; // IsRange means it's a 1 long section indicating a start or an end // s.IsRange = false; // IsRange means it's a 1 long section indicating a start or an end
combined.add(s); combined.add(s);
takenByBigGuy = true;
DebugCommand.SendDebugMessage("Finished section: " + s); DebugCommand.SendDebugMessage("Finished section: " + s);
sendMessageWithPointer(str, s.Start, s.End); sendMessageWithPointer(str, s.Start, s.End);
} else { } else {
DebugCommand.SendDebugMessage("Adding next section: " + section); DebugCommand.SendDebugMessage("Adding next section: " + section);
sendMessageWithPointer(str, section.Start, section.End); sendMessageWithPointer(str, section.Start, section.End);
nextSection.put(section.Formatters.get(0), section); nextSection.put(formatter, section);
takenByBigGuy = false;
} }
DebugCommand DebugCommand
.SendDebugMessage("New area taken: (" + takenStart + "-" + takenEnd + ") " + takenFormatter); .SendDebugMessage("New area taken: (" + takenStart + "-" + takenEnd + ") " + takenFormatter);
@ -200,7 +239,7 @@ public final class ChatFormatter {
return sections; return sections;
} }
private static void addRemChars(ArrayList<FormattedSection> sections, ArrayList<int[]> remchars) { private static void addRemChars(ArrayList<FormattedSection> sections, ArrayList<int[]> remchars, String str) {
sections.stream() sections.stream()
.flatMap(fs -> fs.Formatters.stream().filter(cf -> cf.removeCharCount > 0) .flatMap(fs -> fs.Formatters.stream().filter(cf -> cf.removeCharCount > 0)
.mapToInt(cf -> cf.removeCharCount).mapToObj(rcc -> new int[]{fs.Start, fs.Start + rcc - 1})) .mapToInt(cf -> cf.removeCharCount).mapToObj(rcc -> new int[]{fs.Start, fs.Start + rcc - 1}))
@ -210,31 +249,41 @@ public final class ChatFormatter {
.mapToInt(cf -> cf.removeCharCount).mapToObj(rcc -> new int[]{fs.End - rcc + 1, fs.End})) .mapToInt(cf -> cf.removeCharCount).mapToObj(rcc -> new int[]{fs.End - rcc + 1, fs.End}))
.forEach(remchars::add); .forEach(remchars::add);
DebugCommand.SendDebugMessage("Added remchars:"); DebugCommand.SendDebugMessage("Added remchars:");
DebugCommand DebugCommand.SendDebugMessage(remchars.stream().map(Arrays::toString).collect(Collectors.joining("; ")));
.SendDebugMessage(remchars.stream().map(Arrays::toString).collect(Collectors.joining("; "))); sendMessageWithPointer(str,
remchars.stream().flatMapToInt(Arrays::stream).toArray());
} }
private static void combineSections(String str, ArrayList<FormattedSection> sections) { private static void combineSections(String str, ArrayList<FormattedSection> sections) {
boolean cont = true; for (int i = 1; i < sections.size(); i++) {
boolean found = false;
for (int i = 1; cont; ) {
int nextindex = i + 1;
if (sections.size() < 2)
break;
DebugCommand.SendDebugMessage("i: " + i); DebugCommand.SendDebugMessage("i: " + i);
FormattedSection firstSection = sections.get(i - 1); final FormattedSection firstSection;
final FormattedSection lastSection;
{
FormattedSection firstSect = sections.get(i - 1);
FormattedSection lastSect = sections.get(i);
if (firstSect.Start > lastSect.Start) { //The first can't start later
var section = firstSect;
firstSect = lastSect;
lastSect = section;
}
firstSection = firstSect;
lastSection = lastSect;
}
DebugCommand.SendDebugMessage("Combining sections " + firstSection); DebugCommand.SendDebugMessage("Combining sections " + firstSection);
sendMessageWithPointer(str, firstSection.Start, firstSection.End); sendMessageWithPointer(str, firstSection.Start, firstSection.End);
final FormattedSection lastSection = sections.get(i);
DebugCommand.SendDebugMessage(" and " + lastSection); DebugCommand.SendDebugMessage(" and " + lastSection);
sendMessageWithPointer(str, lastSection.Start, lastSection.End); sendMessageWithPointer(str, lastSection.Start, lastSection.End);
if (firstSection.Start == lastSection.Start && firstSection.End == lastSection.End) { if (firstSection.Start == lastSection.Start && firstSection.End == lastSection.End) {
firstSection.Formatters.addAll(lastSection.Formatters); firstSection.Formatters.addAll(lastSection.Formatters);
firstSection.Matches.addAll(lastSection.Matches); firstSection.Matches.addAll(lastSection.Matches);
firstSection.type = lastSection.type;
DebugCommand.SendDebugMessage("To section " + firstSection); DebugCommand.SendDebugMessage("To section " + firstSection);
sendMessageWithPointer(str, firstSection.Start, firstSection.End); sendMessageWithPointer(str, firstSection.Start, firstSection.End);
sections.remove(i); sections.remove(i);
found = true; i = 0;
sortSections(sections);
continue;
} else if (firstSection.End > lastSection.Start && firstSection.Start < lastSection.End) { } else if (firstSection.End > lastSection.Start && firstSection.Start < lastSection.End) {
int origend2 = firstSection.End; int origend2 = firstSection.End;
firstSection.End = lastSection.Start - 1; firstSection.End = lastSection.Start - 1;
@ -244,7 +293,6 @@ public final class ChatFormatter {
section.Formatters.addAll(lastSection.Formatters); section.Formatters.addAll(lastSection.Formatters);
section.Matches.addAll(lastSection.Matches); // TODO: Clean section.Matches.addAll(lastSection.Matches); // TODO: Clean
sections.add(i, section); sections.add(i, section);
nextindex++;
// Use the properties of the first section not the second one // Use the properties of the first section not the second one
lastSection.Formatters.clear(); lastSection.Formatters.clear();
lastSection.Formatters.addAll(firstSection.Formatters); lastSection.Formatters.addAll(firstSection.Formatters);
@ -256,7 +304,7 @@ public final class ChatFormatter {
Predicate<FormattedSection> removeIfNeeded = s -> { Predicate<FormattedSection> removeIfNeeded = s -> {
if (s.Start < 0 || s.End < 0 || s.Start > s.End) { if (s.Start < 0 || s.End < 0 || s.Start > s.End) {
DebugCommand.SendDebugMessage("Removing section: " + s); DebugCommand.SendDebugMessage(" Removed: " + s);
sendMessageWithPointer(str, s.Start, s.End); sendMessageWithPointer(str, s.Start, s.End);
sections.remove(s); sections.remove(s);
return true; return true;
@ -277,27 +325,19 @@ public final class ChatFormatter {
DebugCommand.SendDebugMessage(" 3:" + lastSection); DebugCommand.SendDebugMessage(" 3:" + lastSection);
sendMessageWithPointer(str, lastSection.Start, lastSection.End); sendMessageWithPointer(str, lastSection.Start, lastSection.End);
} }
found = true; i = 0;
} }
sortSections(sections);
if (i == 0) continue;
for (int j = i - 1; j <= i + 1; j++) { for (int j = i - 1; j <= i + 1; j++) {
if (j < sections.size() && sections.get(j).End < sections.get(j).Start) { if (j < sections.size() && sections.get(j).End < sections.get(j).Start) {
DebugCommand.SendDebugMessage("Removing section: " + sections.get(j)); DebugCommand.SendDebugMessage("Removing section: " + sections.get(j));
sendMessageWithPointer(str, sections.get(j).Start, sections.get(j).End); sendMessageWithPointer(str, sections.get(j).Start, sections.get(j).End);
sections.remove(j); sections.remove(j);
j--; j--;
found = true; i = 0;
} }
} }
i = nextindex - 1;
i++;
if (i >= sections.size()) {
if (found) {
i = 1;
found = false;
sortSections(sections);
} else
cont = false;
}
} }
} }
@ -310,11 +350,13 @@ public final class ChatFormatter {
int start = section.Start, end = section.End; int start = section.Start, end = section.End;
DebugCommand.SendDebugMessage("Start: " + start + " - End: " + end); DebugCommand.SendDebugMessage("Start: " + start + " - End: " + end);
sendMessageWithPointer(str, start, end); sendMessageWithPointer(str, start, end);
val rcs = remchars.stream().filter(rc -> rc[0] <= start && start <= rc[1]).findAny(); /*DebugCommand.SendDebugMessage("RCS: "+remchars.stream().filter(rc -> rc[0] <= start && start <= rc[1]).count());
val rce = remchars.stream().filter(rc -> rc[0] <= end && end <= rc[1]).findAny(); DebugCommand.SendDebugMessage("RCE: "+remchars.stream().filter(rc -> rc[0] <= end && end <= rc[1]).count());
val rci = remchars.stream().filter(rc -> start < rc[0] && rc[1] < end).toArray(int[][]::new); DebugCommand.SendDebugMessage("RCI: "+remchars.stream().filter(rc -> start < rc[0] || rc[1] < end).count());*/
int s = start, e = end; val rci = remchars.stream().filter(rc -> (rc[0] <= start && rc[1] >= start)
if (rcs.isPresent()) || (rc[0] >= start && rc[1] <= end)
|| (rc[0] <= end && rc[1] >= end)).sorted(Comparator.comparingInt(rc -> rc[0] * 10000 + rc[1])).toArray(int[][]::new);
/*if (rcs.isPresent())
s = rcs.get()[1] + 1; s = rcs.get()[1] + 1;
if (rce.isPresent()) if (rce.isPresent())
e = rce.get()[0] - 1; e = rce.get()[0] - 1;
@ -322,12 +364,17 @@ public final class ChatFormatter {
if (e - s < 0) { //e-s==0 means the end char is the same as start char, so one char message if (e - s < 0) { //e-s==0 means the end char is the same as start char, so one char message
DebugCommand.SendDebugMessage("Skipping section because of remchars (length would be " + (e - s + 1) + ")"); DebugCommand.SendDebugMessage("Skipping section because of remchars (length would be " + (e - s + 1) + ")");
continue; continue;
} }*/
originaltext = str.substring(s, e + 1); DebugCommand.SendDebugMessage("Applying RC: " + Arrays.stream(rci).map(Arrays::toString).collect(Collectors.joining(", ", "[", "]")));
originaltext = str.substring(start, end + 1);
val sb = new StringBuilder(originaltext); val sb = new StringBuilder(originaltext);
for (int x = rci.length - 1; x >= 0; x--) for (int x = rci.length - 1; x >= 0; x--)
sb.delete(rci[x][0] - start - 1, rci[x][1] - start); //Delete going backwards sb.delete(Math.max(rci[x][0] - start, 0), Math.min(rci[x][1] - start, end) + 1); //Delete going backwards
originaltext = sb.toString(); originaltext = sb.toString();
if (originaltext.length() == 0) {
DebugCommand.SendDebugMessage("Skipping section because of remchars");
continue;
}
DebugCommand.SendDebugMessage("Section text: " + originaltext); DebugCommand.SendDebugMessage("Section text: " + originaltext);
String openlink = null; String openlink = null;
section.Formatters.sort(Comparator.comparing(cf2 -> cf2.priority.GetValue())); //Apply the highest last, to overwrite previous ones section.Formatters.sort(Comparator.comparing(cf2 -> cf2.priority.GetValue())); //Apply the highest last, to overwrite previous ones
@ -381,7 +428,7 @@ public final class ChatFormatter {
sections.sort( sections.sort(
(s1, s2) -> s1.Start == s2.Start (s1, s2) -> s1.Start == s2.Start
? s1.End == s2.End ? Integer.compare(s2.Formatters.get(0).priority.GetValue(), ? s1.End == s2.End ? Integer.compare(s2.Formatters.get(0).priority.GetValue(),
s1.Formatters.get(0).priority.GetValue()) : Integer.compare(s2.End, s1.End) s1.Formatters.get(0).priority.GetValue()) : Integer.compare(s1.End, s2.End)
: Integer.compare(s1.Start, s2.Start)); : Integer.compare(s1.Start, s2.Start));
} }

View file

@ -2,7 +2,10 @@ package buttondevteam.chat.components.fun;
import buttondevteam.chat.ChatPlayer; import buttondevteam.chat.ChatPlayer;
import buttondevteam.chat.PluginMain; import buttondevteam.chat.PluginMain;
import buttondevteam.lib.chat.*; import buttondevteam.lib.chat.Color;
import buttondevteam.lib.chat.Command2;
import buttondevteam.lib.chat.CommandClass;
import buttondevteam.lib.chat.ICommand2MC;
import buttondevteam.lib.player.TBMCPlayer; import buttondevteam.lib.player.TBMCPlayer;
import org.bukkit.entity.Player; import org.bukkit.entity.Player;
@ -13,7 +16,6 @@ import java.util.Optional;
"Rainbow mode", "Rainbow mode",
"This command allows you to talk in rainbow colors" "This command allows you to talk in rainbow colors"
}) })
@OptionallyPlayerCommandClass(playerOnly = true)
public class CCommand extends ICommand2MC { public class CCommand extends ICommand2MC {
@Command2.Subcommand @Command2.Subcommand
public boolean def(Player player, @Command2.OptionalArg String color) { public boolean def(Player player, @Command2.OptionalArg String color) {

View file

@ -5,7 +5,6 @@ import buttondevteam.chat.PluginMain;
import buttondevteam.lib.chat.Command2; import buttondevteam.lib.chat.Command2;
import buttondevteam.lib.chat.CommandClass; import buttondevteam.lib.chat.CommandClass;
import buttondevteam.lib.chat.ICommand2MC; import buttondevteam.lib.chat.ICommand2MC;
import buttondevteam.lib.chat.TBMCCommandBase;
import buttondevteam.lib.player.TBMCPlayerBase; import buttondevteam.lib.player.TBMCPlayerBase;
import lombok.val; import lombok.val;
import org.bukkit.Bukkit; import org.bukkit.Bukkit;

View file

@ -26,26 +26,41 @@ import org.bukkit.potion.PotionEffect;
import org.bukkit.potion.PotionEffectType; import org.bukkit.potion.PotionEffectType;
import org.bukkit.scheduler.BukkitTask; import org.bukkit.scheduler.BukkitTask;
import java.util.ArrayList; import java.util.HashSet;
import java.util.Random; import java.util.Random;
/**
* Random things I added over the years.
*/
public class FunComponent extends Component<PluginMain> implements Listener { public class FunComponent extends Component<PluginMain> implements Listener {
private boolean ActiveF = false; private boolean ActiveF = false;
private ChatPlayer FPlayer = null; private ChatPlayer FPlayer = null;
private BukkitTask Ftask = null; private BukkitTask Ftask = null;
private ArrayList<CommandSender> Fs = new ArrayList<>(); private HashSet<CommandSender> Fs = new HashSet<>();
private UnlolCommand command; private UnlolCommand command;
private TBMCSystemChatEvent.BroadcastTarget unlolTarget; private TBMCSystemChatEvent.BroadcastTarget unlolTarget;
private TBMCSystemChatEvent.BroadcastTarget fTarget; private TBMCSystemChatEvent.BroadcastTarget fTarget;
/**
* The strings that count as laughs, see unlol.
*/
private ConfigData<String[]> laughStrings() { private ConfigData<String[]> laughStrings() {
return getConfig().getData("laughStrings", () -> new String[]{"xd", "lel", "lawl", "kek", "lmao", "hue", "hah", "rofl"}); return getConfig().getData("laughStrings", () -> new String[]{"xd", "lel", "lawl", "kek", "lmao", "hue", "hah", "rofl"});
} }
/**
* The "Press F to pay respects" meme in Minecraft. It will randomly appear on player death and keep track of how many "F"s are said in chat.
* You can hover over a player's name to see their respect.
*/
private ConfigData<Boolean> respect() { private ConfigData<Boolean> respect() {
return getConfig().getData("respect", true); return getConfig().getData("respect", true);
} }
/**
* This is an inside joke on our server.
* It keeps track of laughs (lols and what's defined in laughStrings) and if someone does /unlol or /unlaugh it will unlaugh the last person who laughed.
* Which also blinds the laughing person for a few seconds. This action can only be performed once per laugh.
*/
private ConfigData<Boolean> unlol() { private ConfigData<Boolean> unlol() {
return getConfig().getData("unlol", true); return getConfig().getData("unlol", true);
} }
@ -105,7 +120,7 @@ public class FunComponent extends Component<PluginMain> implements Listener {
FPlayer.FCount().set(FPlayer.FCount().get() + Fs.size()); FPlayer.FCount().set(FPlayer.FCount().get() + Fs.size());
TBMCChatAPI.SendSystemMessage(Channel.GlobalChat, Channel.RecipientTestResult.ALL, TBMCChatAPI.SendSystemMessage(Channel.GlobalChat, Channel.RecipientTestResult.ALL,
"§b" + Fs.size() + " " + (Fs.size() == 1 ? "person" : "people") "§b" + Fs.size() + " " + (Fs.size() == 1 ? "person" : "people")
+ " paid their respects.§r", fTarget); + " paid their respects.§r", fTarget);
Fs.clear(); Fs.clear();
} }
}; };
@ -119,9 +134,10 @@ public class FunComponent extends Component<PluginMain> implements Listener {
FPlayer.FDeaths().set(FPlayer.FDeaths().get() + 1); FPlayer.FDeaths().set(FPlayer.FDeaths().get() + 1);
TBMCChatAPI.SendSystemMessage(Channel.GlobalChat, Channel.RecipientTestResult.ALL, TBMCChatAPI.SendSystemMessage(Channel.GlobalChat, Channel.RecipientTestResult.ALL,
"§bPress F to pay respects.§r", fTarget); "§bPress F to pay respects.§r", fTarget);
Bukkit.getScheduler().runTaskLaterAsynchronously(PluginMain.Instance, tt, 15 * 20); Ftask = Bukkit.getScheduler().runTaskLaterAsynchronously(PluginMain.Instance, tt, 15 * 20);
} }
} }
@EventHandler @EventHandler
public void onPlayerLeave(PlayerQuitEvent event) { public void onPlayerLeave(PlayerQuitEvent event) {
if (unlol().get()) if (unlol().get())

View file

@ -6,7 +6,6 @@ import buttondevteam.chat.components.towny.TownyComponent;
import buttondevteam.lib.chat.Color; import buttondevteam.lib.chat.Color;
import buttondevteam.lib.chat.Command2; import buttondevteam.lib.chat.Command2;
import buttondevteam.lib.chat.CommandClass; import buttondevteam.lib.chat.CommandClass;
import buttondevteam.lib.chat.OptionallyPlayerCommandClass;
import com.palmergames.bukkit.towny.object.Resident; import com.palmergames.bukkit.towny.object.Resident;
import com.palmergames.bukkit.towny.object.Town; import com.palmergames.bukkit.towny.object.Town;
import org.bukkit.ChatColor; import org.bukkit.ChatColor;
@ -16,7 +15,6 @@ import java.util.ArrayList;
import java.util.Arrays; import java.util.Arrays;
import java.util.stream.Collectors; import java.util.stream.Collectors;
@OptionallyPlayerCommandClass(playerOnly = true)
@CommandClass(helpText = { @CommandClass(helpText = {
"Name color", // "Name color", //
"This command allows you to set how the town colors look on your name.", // "This command allows you to set how the town colors look on your name.", //

View file

@ -5,7 +5,6 @@ import buttondevteam.chat.components.towny.TownyComponent;
import buttondevteam.lib.TBMCCoreAPI; import buttondevteam.lib.TBMCCoreAPI;
import buttondevteam.lib.chat.Command2; import buttondevteam.lib.chat.Command2;
import buttondevteam.lib.chat.CommandClass; import buttondevteam.lib.chat.CommandClass;
import buttondevteam.lib.chat.OptionallyPlayerCommandClass;
import com.palmergames.bukkit.towny.exceptions.NotRegisteredException; import com.palmergames.bukkit.towny.exceptions.NotRegisteredException;
import com.palmergames.bukkit.towny.object.Nation; import com.palmergames.bukkit.towny.object.Nation;
import com.palmergames.bukkit.towny.object.Resident; import com.palmergames.bukkit.towny.object.Resident;
@ -17,7 +16,6 @@ import org.bukkit.entity.Player;
"Each town in the nation will have it's first color (border) set to this color.", // "Each town in the nation will have it's first color (border) set to this color.", //
"See the help text for /u towncolor for more details.", // "See the help text for /u towncolor for more details.", //
}) })
@OptionallyPlayerCommandClass(playerOnly = true)
public class NationColorCommand extends UCommandBase { public class NationColorCommand extends UCommandBase {
@Command2.Subcommand @Command2.Subcommand
public boolean def(Player player, String color) { public boolean def(Player player, String color) {

View file

@ -5,7 +5,6 @@ import buttondevteam.chat.components.towny.TownyComponent;
import buttondevteam.lib.TBMCCoreAPI; import buttondevteam.lib.TBMCCoreAPI;
import buttondevteam.lib.chat.Command2; import buttondevteam.lib.chat.Command2;
import buttondevteam.lib.chat.CommandClass; import buttondevteam.lib.chat.CommandClass;
import buttondevteam.lib.chat.OptionallyPlayerCommandClass;
import com.palmergames.bukkit.towny.exceptions.NotRegisteredException; import com.palmergames.bukkit.towny.exceptions.NotRegisteredException;
import com.palmergames.bukkit.towny.object.Resident; import com.palmergames.bukkit.towny.object.Resident;
import com.palmergames.bukkit.towny.object.Town; import com.palmergames.bukkit.towny.object.Town;
@ -21,7 +20,6 @@ import java.lang.reflect.Method;
"The town will be shown with this color on Dynmap and all players in the town will appear in chat with these colors.", // "The town will be shown with this color on Dynmap and all players in the town will appear in chat with these colors.", //
"The colors will split the name evenly but residents can override that with /u ncolor.", // "The colors will split the name evenly but residents can override that with /u ncolor.", //
}) // TODO: /u u when annotation not present }) // TODO: /u u when annotation not present
@OptionallyPlayerCommandClass(playerOnly = true)
@RequiredArgsConstructor @RequiredArgsConstructor
public class TownColorCommand extends UCommandBase { public class TownColorCommand extends UCommandBase {
private final TownColorComponent component; private final TownColorComponent component;

View file

@ -23,8 +23,8 @@ import org.bukkit.configuration.file.YamlConfiguration;
import org.bukkit.entity.Player; import org.bukkit.entity.Player;
import org.bukkit.event.EventHandler; import org.bukkit.event.EventHandler;
import org.bukkit.event.Listener; import org.bukkit.event.Listener;
import org.bukkit.plugin.Plugin;
import org.dynmap.towny.DTBridge; import org.dynmap.towny.DTBridge;
import org.dynmap.towny.DynmapTownyPlugin;
import java.io.File; import java.io.File;
import java.util.*; import java.util.*;
@ -34,6 +34,10 @@ import java.util.function.Consumer;
import java.util.function.Function; import java.util.function.Function;
import java.util.stream.Collectors; import java.util.stream.Collectors;
/**
* Town colors for Towny. It allows mayors and kings to set a color for their town/nation (nation can be disabled).
* This color is applied to the player names in chat and on Dynmap, if used.
*/
@ComponentMetadata(depends = TownyComponent.class) @ComponentMetadata(depends = TownyComponent.class)
public class TownColorComponent extends Component<PluginMain> implements Listener { public class TownColorComponent extends Component<PluginMain> implements Listener {
/** /**
@ -45,10 +49,17 @@ public class TownColorComponent extends Component<PluginMain> implements Listene
*/ */
public static Map<String, Color> NationColor = new HashMap<>(); public static Map<String, Color> NationColor = new HashMap<>();
/**
* The amount of town colors allowed. If more than one is used, players can change how many letters to be in a specific color using /u ncolor.
*/
public ConfigData<Byte> colorCount() { public ConfigData<Byte> colorCount() {
return getConfig().getData("colorCount", (byte) 1, cc -> ((Integer) cc).byteValue(), Byte::intValue); return getConfig().getData("colorCount", (byte) 1, cc -> ((Integer) cc).byteValue(), Byte::intValue);
} }
/**
* If enabled, players will have a nation-defined color in addition to town colors, white by default.
* They can change how much of each color they want with this as well.
*/
public ConfigData<Boolean> useNationColors() { public ConfigData<Boolean> useNationColors() {
return getConfig().getData("useNationColors", true); return getConfig().getData("useNationColors", true);
} }
@ -60,7 +71,6 @@ public class TownColorComponent extends Component<PluginMain> implements Listene
@Override @Override
protected void enable() { protected void enable() {
component = this; component = this;
//TODO: Don't register all commands automatically (welp)
Consumer<ConfigurationSection> loadTC = cs -> TownColorComponent.TownColors.putAll(cs.getValues(true).entrySet().stream() Consumer<ConfigurationSection> loadTC = cs -> TownColorComponent.TownColors.putAll(cs.getValues(true).entrySet().stream()
.collect(Collectors.toMap(Map.Entry::getKey, v -> ((List<String>) v.getValue()).stream() .collect(Collectors.toMap(Map.Entry::getKey, v -> ((List<String>) v.getValue()).stream()
.map(Color::valueOf).toArray(Color[]::new)))); .map(Color::valueOf).toArray(Color[]::new))));
@ -85,25 +95,7 @@ public class TownColorComponent extends Component<PluginMain> implements Listene
if (usenc) if (usenc)
NationColor.keySet().removeIf(n -> !TownyComponent.TU.getNationsMap().containsKey(n)); // Removes nation colors for deleted/renamed nations NationColor.keySet().removeIf(n -> !TownyComponent.TU.getNationsMap().containsKey(n)); // Removes nation colors for deleted/renamed nations
Bukkit.getScheduler().runTask(getPlugin(), () -> { initDynmap();
val dtp = (DynmapTownyPlugin) Bukkit.getPluginManager().getPlugin("Dynmap-Towny");
if (dtp == null)
return;
for (val entry : TownColors.entrySet()) {
try {
val town = TownyComponent.TU.getTownsMap().get(entry.getKey());
Nation nation;
Color nc;
if (!useNationColors().get())
nc = null;
else if (!town.hasNation() || (nation = town.getNation()) == null || (nc = NationColor.get(nation.getName().toLowerCase())) == null)
nc = Color.White;
setTownColor(dtp, buttondevteam.chat.components.towncolors.admin.TownColorCommand.getTownNameCased(entry.getKey()), entry.getValue(), nc);
} catch (Exception e) {
TBMCCoreAPI.SendException("Error while setting town color for town " + entry.getKey() + "!", e);
}
}
});
registerCommand(new TownColorCommand(this)); registerCommand(new TownColorCommand(this));
if (useNationColors().get()) if (useNationColors().get())
@ -126,6 +118,28 @@ public class TownColorComponent extends Component<PluginMain> implements Listene
v -> v.getValue().toString()))); v -> v.getValue().toString())));
} }
private void initDynmap() {
Bukkit.getScheduler().runTask(getPlugin(), () -> {
val dtp = Bukkit.getPluginManager().getPlugin("Dynmap-Towny");
if (dtp == null)
return;
for (val entry : TownColors.entrySet()) {
try {
val town = TownyComponent.TU.getTownsMap().get(entry.getKey());
Nation nation;
Color nc;
if (!useNationColors().get())
nc = null;
else if (!town.hasNation() || (nation = town.getNation()) == null || (nc = NationColor.get(nation.getName().toLowerCase())) == null)
nc = Color.White;
setTownColor(dtp, buttondevteam.chat.components.towncolors.admin.TownColorCommand.getTownNameCased(entry.getKey()), entry.getValue(), nc);
} catch (Exception e) {
TBMCCoreAPI.SendException("Error while setting town color for town " + entry.getKey() + "!", e);
}
}
});
}
/** /**
* Sets a town's color on Dynmap. * Sets a town's color on Dynmap.
* *
@ -133,8 +147,7 @@ public class TownColorComponent extends Component<PluginMain> implements Listene
* @param town The town's name using the correct casing * @param town The town's name using the correct casing
* @param colors The town's colors * @param colors The town's colors
*/ */
public static void setTownColor(Plugin dtp, String town, Color[] colors, Color nationcolor) {
public static void setTownColor(DynmapTownyPlugin dtp, String town, Color[] colors, Color nationcolor) {
Function<Color, Integer> c2i = c -> c.getRed() << 16 | c.getGreen() << 8 | c.getBlue(); Function<Color, Integer> c2i = c -> c.getRed() << 16 | c.getGreen() << 8 | c.getBlue();
try { try {
DTBridge.setTownColor(dtp, town, c2i.apply(nationcolor == null ? colors[0] : nationcolor), DTBridge.setTownColor(dtp, town, c2i.apply(nationcolor == null ? colors[0] : nationcolor),

View file

@ -11,7 +11,6 @@ import com.palmergames.bukkit.towny.object.Town;
import lombok.val; import lombok.val;
import org.bukkit.Bukkit; import org.bukkit.Bukkit;
import org.bukkit.command.CommandSender; import org.bukkit.command.CommandSender;
import org.dynmap.towny.DynmapTownyPlugin;
import java.util.Arrays; import java.util.Arrays;
import java.util.Map; import java.util.Map;
@ -39,52 +38,52 @@ public class TownColorCommand extends AdminCommandBase { //TODO: Command path al
Color[] clrs = new Color[colors.length]; Color[] clrs = new Color[colors.length];
for (int i = 0; i < colors.length; i++) { for (int i = 0; i < colors.length; i++) {
val c = getColorOrSendError(colors[i], sender); val c = getColorOrSendError(colors[i], sender);
if (!c.isPresent()) if (!c.isPresent())
return true; return true;
clrs[i] = c.get(); clrs[i] = c.get();
} }
Color tnc; Color tnc;
boolean usenc = TownColorComponent.getComponent().useNationColors().get(); boolean usenc = TownColorComponent.getComponent().useNationColors().get();
if (usenc) { if (usenc) {
try { try {
tnc = TownColorComponent.NationColor.get(town.getNation().getName().toLowerCase()); tnc = TownColorComponent.NationColor.get(town.getNation().getName().toLowerCase());
} catch (Exception e) { } catch (Exception e) {
tnc = null; tnc = null;
} }
if (tnc == null) tnc = Color.White; //Default nation color - TODO: Make configurable if (tnc == null) tnc = Color.White; //Default nation color - TODO: Make configurable
} else tnc = null; } else tnc = null;
for (Map.Entry<String, Color[]> other : TownColorComponent.TownColors.entrySet()) { for (Map.Entry<String, Color[]> other : TownColorComponent.TownColors.entrySet()) {
Color nc; Color nc;
if (usenc) { if (usenc) {
try { try {
nc = TownColorComponent.NationColor.get(TownyComponent.TU.getTownsMap().get(other.getKey()).getNation().getName().toLowerCase()); nc = TownColorComponent.NationColor.get(TownyComponent.TU.getTownsMap().get(other.getKey()).getNation().getName().toLowerCase());
} catch (Exception e) { //Too lazy for lots of null-checks and it may throw exceptions anyways } catch (Exception e) { //Too lazy for lots of null-checks and it may throw exceptions anyways
nc = null; nc = null;
} }
if (nc == null) nc = Color.White; //Default nation color if (nc == null) nc = Color.White; //Default nation color
} else nc = null; } else nc = null;
if (!usenc || nc.getName().equals(tnc.getName())) { if (!usenc || nc.getName().equals(tnc.getName())) {
int C = 0; int C = 0;
if (clrs.length == other.getValue().length) if (clrs.length == other.getValue().length)
for (int i = 0; i < clrs.length; i++) for (int i = 0; i < clrs.length; i++)
if (clrs[i].getName().equals(other.getValue()[i].getName())) if (clrs[i].getName().equals(other.getValue()[i].getName()))
C++; C++;
else break; else break;
if (C == clrs.length) { if (C == clrs.length) {
sender.sendMessage("§cThis town color combination is already used!"); sender.sendMessage("§cThis town color combination is already used!");
return true; return true;
} }
} }
} }
TownColorComponent.TownColors.put(town.getName().toLowerCase(), clrs); TownColorComponent.TownColors.put(town.getName().toLowerCase(), clrs);
TownyListener.updateTownMembers(town); TownyListener.updateTownMembers(town);
val dtp = (DynmapTownyPlugin) Bukkit.getPluginManager().getPlugin("Dynmap-Towny"); val dtp = Bukkit.getPluginManager().getPlugin("Dynmap-Towny");
if (dtp != null) //If it's not found then it's not loaded, it'll be noticed by the admins if needed if (dtp != null) //If it's not found then it's not loaded, it'll be noticed by the admins if needed
TownColorComponent.setTownColor(dtp, town.getName(), clrs, tnc); TownColorComponent.setTownColor(dtp, town.getName(), clrs, tnc);
sender.sendMessage("§bColor(s) set."); sender.sendMessage("§bColor(s) set.");
return true; return true;
} }
public static Optional<Color> getColorOrSendError(String name, CommandSender sender) { public static Optional<Color> getColorOrSendError(String name, CommandSender sender) {
val c = Arrays.stream(Color.values()).skip(1).filter(cc -> cc.getName().equalsIgnoreCase(name)).findAny(); val c = Arrays.stream(Color.values()).skip(1).filter(cc -> cc.getName().equalsIgnoreCase(name)).findAny();
@ -102,5 +101,5 @@ public class TownColorCommand extends AdminCommandBase { //TODO: Command path al
public static String getTownNameCased(String name) { public static String getTownNameCased(String name) {
return TownyComponent.TU.getTownsMap().get(name.toLowerCase()).getName(); return TownyComponent.TU.getTownsMap().get(name.toLowerCase()).getName();
} }
} }

View file

@ -22,6 +22,10 @@ import java.util.Optional;
import java.util.function.Function; import java.util.function.Function;
import java.util.stream.Collectors; import java.util.stream.Collectors;
/**
* This component manages the town and nation chat. It's also needed for the TownColorComponent.
* It provides the TC and NC channels, and posts Towny messages (global, town, nation) to the correct channels for other platforms like Discord.
*/
public class TownyComponent extends Component<PluginMain> { public class TownyComponent extends Component<PluginMain> {
public static TownyUniverse TU; public static TownyUniverse TU;
private static ArrayList<String> Towns; private static ArrayList<String> Towns;

View file

@ -57,7 +57,8 @@ public class PlayerJoinLeaveListener implements Listener {
nwithoutformatting = p.getName(); nwithoutformatting = p.getName();
PlayerListener.nicknames.forcePut(nwithoutformatting.toLowerCase(), p.getUniqueId()); //TODO: FormatterComponent PlayerListener.nicknames.forcePut(nwithoutformatting.toLowerCase(), p.getUniqueId()); //TODO: FormatterComponent
HistoryCommand.showHistory(e.getPlayer(), null); if (PluginMain.Instance.storeChatHistory().get())
HistoryCommand.showHistory(e.getPlayer(), null);
} }
@EventHandler @EventHandler

View file

@ -161,6 +161,8 @@ public class PlayerListener implements Listener {
} }
} }
private long lastError = 0;
@EventHandler @EventHandler
public void onPlayerTBMCChat(TBMCChatEvent e) { public void onPlayerTBMCChat(TBMCChatEvent e) {
try { try {
@ -169,6 +171,13 @@ public class PlayerListener implements Listener {
HistoryCommand.addChatMessage(e.getCm(), e.getChannel()); HistoryCommand.addChatMessage(e.getCm(), e.getChannel());
e.setCancelled(FormatterComponent.handleChat(e)); e.setCancelled(FormatterComponent.handleChat(e));
} catch (NoClassDefFoundError | Exception ex) { // Weird things can happen } catch (NoClassDefFoundError | Exception ex) { // Weird things can happen
if (lastError < System.nanoTime() - 1000L * 1000L * 1000L * 60 * 60 //60 mins
&& Bukkit.getOnlinePlayers().size() > 0) { //If there are no players on, display to the first person
lastError = System.nanoTime(); //I put the whole thing in the if to protect against race conditions
for (Player p : Bukkit.getOnlinePlayers())
if (e.shouldSendTo(p))
p.sendMessage("[" + e.getChannel().DisplayName().get() + "] §cSome features in the message below might be unavailable due to an error.");
}
ChatUtils.sendChatMessage(e, s -> "§c!§r" + s); ChatUtils.sendChatMessage(e, s -> "§c!§r" + s);
TBMCCoreAPI.SendException("An error occured while processing a chat message!", ex); TBMCCoreAPI.SendException("An error occured while processing a chat message!", ex);
} }

View file

@ -3,6 +3,7 @@ package org.dynmap.towny;
import lombok.val; import lombok.val;
import org.bukkit.Bukkit; import org.bukkit.Bukkit;
import org.bukkit.configuration.file.FileConfiguration; import org.bukkit.configuration.file.FileConfiguration;
import org.bukkit.plugin.Plugin;
import org.dynmap.bukkit.DynmapPlugin; import org.dynmap.bukkit.DynmapPlugin;
import org.dynmap.markers.MarkerAPI; import org.dynmap.markers.MarkerAPI;
@ -14,32 +15,27 @@ import java.util.Map;
public class DTBridge { public class DTBridge {
/** /**
* Sets the town color on Dynmap. * Sets the town color on Dynmap.
* *
* @param dtp * @param dtp The Dynmap-Towny plugin
* The Dynmap-Towny plugin * @param townname The name of the town, using correct casing
* @param townname * @param strokecolor The stroke color in RGB format
* The name of the town, using correct casing * @param fillcolor The fill color in RGB format
* @param strokecolor * @throws Exception When couldn't set the town color
* The stroke color in RGB format
* @param fillcolor
* The fill color in RGB format
* @throws Exception
* When couldn't set the town color
*/ */
public static void setTownColor(DynmapTownyPlugin dtp, String townname, int strokecolor, int fillcolor) public static void setTownColor(Plugin dtp, String townname, int strokecolor, int fillcolor)
throws ClassNotFoundException, NoSuchFieldException, SecurityException, IllegalArgumentException, // Keeping these because why not throws ClassNotFoundException, NoSuchFieldException, SecurityException, IllegalArgumentException, // Keeping these because why not
IllegalAccessException, NoSuchMethodException, InstantiationException, InvocationTargetException { IllegalAccessException, NoSuchMethodException, InstantiationException, InvocationTargetException {
Class<?> cl = Class.forName(DynmapTownyPlugin.class.getName() + "$AreaStyle"); Class<?> cl = Class.forName(DynmapTownyPlugin.class.getName() + "$AreaStyle");
Field field = DynmapTownyPlugin.class.getDeclaredField("cusstyle"); Field field = DynmapTownyPlugin.class.getDeclaredField("cusstyle");
field.setAccessible(true); // Doesn't allow accessing it from the same package, if it's from a different plugin field.setAccessible(true); // Doesn't allow accessing it from the same package, if it's from a different plugin
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
val map = (Map<String, Object>) field.get(dtp); val map = (Map<String, Object>) field.get(dtp);
Object style = map.get(townname); Object style = map.get(townname);
if (style == null) { if (style == null) {
Constructor<?> c = cl.getDeclaredConstructor(FileConfiguration.class, String.class, MarkerAPI.class); Constructor<?> c = cl.getDeclaredConstructor(FileConfiguration.class, String.class, MarkerAPI.class);
c.setAccessible(true); c.setAccessible(true);
style = c.newInstance(dtp.getConfig(), "custstyle." + townname, style = c.newInstance(dtp.getConfig(), "custstyle." + townname,
((DynmapPlugin) Bukkit.getPluginManager().getPlugin("dynmap")).getMarkerAPI()); ((DynmapPlugin) Bukkit.getPluginManager().getPlugin("dynmap")).getMarkerAPI());
map.put(townname, style); map.put(townname, style);
} }
set(cl, style, "fillcolor", fillcolor); set(cl, style, "fillcolor", fillcolor);
@ -47,7 +43,7 @@ public class DTBridge {
} }
private static <T> void set(Class<?> cl, Object style, String fieldname, T value) private static <T> void set(Class<?> cl, Object style, String fieldname, T value)
throws NoSuchFieldException, SecurityException, IllegalArgumentException, IllegalAccessException { throws NoSuchFieldException, SecurityException, IllegalArgumentException, IllegalAccessException {
Field field = cl.getDeclaredField(fieldname); Field field = cl.getDeclaredField(fieldname);
field.setAccessible(true); field.setAccessible(true);
field.set(style, value); field.set(style, value);

View file

@ -40,10 +40,6 @@ soft-depend:
- Dynmap-Towny - Dynmap-Towny
- Towny - Towny
permissions: permissions:
tbmc.admin:
description: Gives access to /un- commands and /u admin commands
tbmc.rainbow:
description: Gives access to rainbow colors (/u c).
tbmc.badge.gold: tbmc.badge.gold:
description: Gives a patron badge. description: Gives a patron badge.
default: false default: false

View file

@ -37,36 +37,41 @@ public class ChatFormatIT {
list.add(new ChatFormatIT(sender, "*test*", new TellrawPart("test").setItalic(true).setColor(Color.White))); list.add(new ChatFormatIT(sender, "*test*", new TellrawPart("test").setItalic(true).setColor(Color.White)));
list.add(new ChatFormatIT(sender, "**test**", new TellrawPart("test").setBold(true).setColor(Color.White))); list.add(new ChatFormatIT(sender, "**test**", new TellrawPart("test").setBold(true).setColor(Color.White)));
list.add(new ChatFormatIT(sender, "***test***", list.add(new ChatFormatIT(sender, "***test***",
new TellrawPart("test").setBold(true).setItalic(true).setColor(Color.White))); new TellrawPart("test").setBold(true).setItalic(true).setColor(Color.White)));
list.add(new ChatFormatIT(sender, "***_test_***", list.add(new ChatFormatIT(sender, "***__test__***",
new TellrawPart("test").setBold(true).setItalic(true).setUnderlined(true).setColor(Color.White))); new TellrawPart("test").setBold(true).setItalic(true).setUnderlined(true).setColor(Color.White)));
list.add(new ChatFormatIT(sender, "***_~~test~~_***", new TellrawPart("test").setBold(true).setItalic(true) list.add(new ChatFormatIT(sender, "***__~~test~~__***", new TellrawPart("test").setBold(true).setItalic(true)
.setUnderlined(true).setStrikethrough(true).setColor(Color.White))); .setUnderlined(true).setStrikethrough(true).setColor(Color.White)));
list.add(new ChatFormatIT(sender, "¯\\\\\\_(ツ)\\_/¯", new TellrawPart("¯\\_(ツ)_/¯").setColor(Color.White))); list.add(new ChatFormatIT(sender, "¯\\\\\\_(ツ)\\_/¯", new TellrawPart("¯\\_(ツ)_/¯").setColor(Color.White)));
list.add(new ChatFormatIT(sender, "https://google.hu/", list.add(new ChatFormatIT(sender, "https://google.hu/",
new TellrawPart("https://google.hu/").setColor(Color.White).setUnderlined(true) new TellrawPart("https://google.hu/").setColor(Color.White).setUnderlined(true)
.setHoverEvent(TellrawEvent.create(HoverAction.SHOW_TEXT, .setHoverEvent(TellrawEvent.create(HoverAction.SHOW_TEXT,
new TellrawPart("Click to open").setColor(Color.Blue))) new TellrawPart("Click to open").setColor(Color.Blue)))
.setClickEvent(TellrawEvent.create(ClickAction.OPEN_URL, "https://google.hu/")))); .setClickEvent(TellrawEvent.create(ClickAction.OPEN_URL, "https://google.hu/"))));
list.add(new ChatFormatIT(sender, "*test", new TellrawPart("*test").setColor(Color.White))); list.add(new ChatFormatIT(sender, "*test", new TellrawPart("*test").setColor(Color.White)));
list.add(new ChatFormatIT(sender, "**test*", new TellrawPart("**test*").setColor(Color.White))); list.add(new ChatFormatIT(sender, "**test*", new TellrawPart("**test*").setColor(Color.White)));
list.add(new ChatFormatIT(sender, "***test", new TellrawPart("***test").setColor(Color.White))); list.add(new ChatFormatIT(sender, "***test", new TellrawPart("***test").setColor(Color.White)));
list.add(new ChatFormatIT(sender, "Koiiev", new TellrawPart("§bKoiiev§r").setColor(Color.Aqua))); list.add(new ChatFormatIT(sender, "Koiiev", new TellrawPart("§bKoiiev§r").setColor(Color.Aqua)));
list.add(new ChatFormatIT(sender, "norbipeti", new TellrawPart("§bNorbiPeti§r").setColor(Color.Aqua))); list.add(new ChatFormatIT(sender, "norbipeti", new TellrawPart("§bNorbiPeti§r").setColor(Color.Aqua)));
list.add(new ChatFormatIT(sender, "Arsen_Derby_FTW", new TellrawPart("§bArsen_Derby_FTW§r").setColor(Color.Aqua))); list.add(new ChatFormatIT(sender, "Arsen_Derby_FTW", new TellrawPart("§bArsen_Derby_FTW§r").setColor(Color.Aqua)));
list.add(new ChatFormatIT(sender, "carrot_lynx", new TellrawPart("§bcarrot_lynx§r").setColor(Color.Aqua))); list.add(new ChatFormatIT(sender, "carrot_lynx", new TellrawPart("§bcarrot_lynx§r").setColor(Color.Aqua)));
list.add(new ChatFormatIT(sender, "*carrot_lynx*", new TellrawPart("§bcarrot_lynx§r").setItalic(true).setColor(Color.Aqua))); list.add(new ChatFormatIT(sender, "*carrot_lynx*", new TellrawPart("§bcarrot_lynx§r").setItalic(true).setColor(Color.Aqua)));
list.add(new ChatFormatIT(sender, "https://norbipeti.github.io/", new TellrawPart("https://norbipeti.github.io/") list.add(new ChatFormatIT(sender, "https://norbipeti.github.io/", new TellrawPart("https://norbipeti.github.io/")
.setColor(Color.White).setUnderlined(true) .setColor(Color.White).setUnderlined(true)
.setHoverEvent(TellrawEvent.create(HoverAction.SHOW_TEXT, .setHoverEvent(TellrawEvent.create(HoverAction.SHOW_TEXT,
new TellrawPart("Click to open").setColor(Color.Blue))) new TellrawPart("Click to open").setColor(Color.Blue)))
.setClickEvent(TellrawEvent.create(ClickAction.OPEN_URL, "https://norbipeti.github.io/")))); .setClickEvent(TellrawEvent.create(ClickAction.OPEN_URL, "https://norbipeti.github.io/"))));
list.add(new ChatFormatIT(sender, "*https://norbipeti.github.io/ heh*", new TellrawPart("https://norbipeti.github.io/").setItalic(true).setUnderlined(true) list.add(new ChatFormatIT(sender, "*https://norbipeti.github.io/ heh*", new TellrawPart("https://norbipeti.github.io/").setItalic(true).setUnderlined(true)
.setHoverEvent(TellrawEvent.create(HoverAction.SHOW_TEXT, .setHoverEvent(TellrawEvent.create(HoverAction.SHOW_TEXT,
new TellrawPart("Click to open").setColor(Color.Blue))) new TellrawPart("Click to open").setColor(Color.Blue)))
.setClickEvent(TellrawEvent.create(ClickAction.OPEN_URL, "https://norbipeti.github.io/")), new TellrawPart(" heh").setItalic(true))); .setClickEvent(TellrawEvent.create(ClickAction.OPEN_URL, "https://norbipeti.github.io/")), new TellrawPart(" heh").setItalic(true)));
list.add(new ChatFormatIT(sender, "*test _test_ test*", new TellrawPart("test ").setItalic(true).setColor(Color.White), list.add(new ChatFormatIT(sender, "*test _test_ test*", new TellrawPart("test test test").setItalic(true).setColor(Color.White)));
new TellrawPart("test").setItalic(true).setUnderlined(true).setColor(Color.White), new TellrawPart(" test").setItalic(true).setColor(Color.White))); list.add(new ChatFormatIT(sender, "*test __test__ test*", new TellrawPart("test ").setItalic(true).setColor(Color.White),
new TellrawPart("test").setItalic(true).setUnderlined(true).setColor(Color.White), new TellrawPart(" test").setItalic(true).setColor(Color.White)));
list.add(new ChatFormatIT(sender, "**test __test__ test**", new TellrawPart("test ").setBold(true).setColor(Color.White),
new TellrawPart("test").setBold(true).setUnderlined(true).setColor(Color.White), new TellrawPart(" test").setBold(true).setColor(Color.White)));
list.add(new ChatFormatIT(sender, "**test _test_ test**", new TellrawPart("test ").setBold(true).setColor(Color.White),
new TellrawPart("test").setItalic(true).setBold(true).setColor(Color.White), new TellrawPart(" test").setBold(true).setColor(Color.White)));
list.add(new ChatFormatIT(sender, "https://norbipeti.github.io/test?test&test#test", new TellrawPart("https://norbipeti.github.io/test?test&test#test") list.add(new ChatFormatIT(sender, "https://norbipeti.github.io/test?test&test#test", new TellrawPart("https://norbipeti.github.io/test?test&test#test")
.setColor(Color.White).setUnderlined(true) .setColor(Color.White).setUnderlined(true)
.setHoverEvent(TellrawEvent.create(HoverAction.SHOW_TEXT, .setHoverEvent(TellrawEvent.create(HoverAction.SHOW_TEXT,
@ -77,6 +82,11 @@ public class ChatFormatIT {
.setHoverEvent(TellrawEvent.create(HoverAction.SHOW_TEXT, .setHoverEvent(TellrawEvent.create(HoverAction.SHOW_TEXT,
new TellrawPart("Click to open").setColor(Color.Blue))) new TellrawPart("Click to open").setColor(Color.Blue)))
.setClickEvent(TellrawEvent.create(ClickAction.OPEN_URL, "https://norbipeti.github.io/test")))); .setClickEvent(TellrawEvent.create(ClickAction.OPEN_URL, "https://norbipeti.github.io/test"))));
TellrawPart space = new TellrawPart(" ").setColor(Color.White);
list.add(new ChatFormatIT(sender, "A rainbow text for testing. O", new TellrawPart("A").setColor(Color.Red),
space, new TellrawPart("rainbow").setColor(Color.Gold), space, new TellrawPart("text").setColor(Color.Yellow),
space, new TellrawPart("for").setColor(Color.Green), space, new TellrawPart("testing.").setColor(Color.Blue),
space, new TellrawPart("O").setColor(Color.DarkPurple)).setRainbowMode());
return list; return list;
} }
@ -84,6 +94,7 @@ public class ChatFormatIT {
private final CommandSender sender; private final CommandSender sender;
private final String message; private final String message;
private final TellrawPart[] extras; private final TellrawPart[] extras;
private boolean rainbowMode;
public ChatFormatIT(CommandSender sender, String message, TellrawPart... expectedextras) { public ChatFormatIT(CommandSender sender, String message, TellrawPart... expectedextras) {
this.sender = sender; this.sender = sender;
@ -91,10 +102,17 @@ public class ChatFormatIT {
this.extras = expectedextras; this.extras = expectedextras;
} }
private ChatFormatIT setRainbowMode() {
rainbowMode = true;
return this;
}
@Test @Test
public void testMessage() { public void testMessage() {
ArrayList<ChatFormatter> cfs = ChatProcessing.addFormatters(Color.White, p -> true); ArrayList<ChatFormatter> cfs = ChatProcessing.addFormatters(Color.White, p -> true, null);
final String chid = ChatProcessing.getChannelID(Channel.GlobalChat, ChatUtils.MCORIGIN); final String chid = ChatProcessing.getChannelID(Channel.GlobalChat, ChatUtils.MCORIGIN);
if (rainbowMode)
ChatProcessing.createRPC(Color.White, cfs);
final TellrawPart tp = ChatProcessing.createTellraw(sender, message, null, null, null, chid, ChatUtils.MCORIGIN); final TellrawPart tp = ChatProcessing.createTellraw(sender, message, null, null, null, chid, ChatUtils.MCORIGIN);
ChatFormatter.Combine(cfs, message, tp, null); ChatFormatter.Combine(cfs, message, tp, null);
System.out.println("Testing: " + message); System.out.println("Testing: " + message);