Compare commits

...

36 commits
dev ... master

Author SHA1 Message Date
Norbi Peti d1515c2ab2
Fix using delegated config properties from the Core 2023-07-01 20:11:19 +02:00
Norbi Peti 512a62d75c
Fix remaining test cases for formatting
- Fixed name mentioning test check
- Removed legacy tell raw stuff
- Fixed RPC sections getting combined because the settings weren't updated before checking if they are the same
- Fixed spoiler test assuming and expecting the hover text to be white
#130
2023-06-28 23:56:35 +02:00
Norbi Peti b5fd834dc7
Fix chat tests with MockBukkit and fix Paper version
#130
2023-06-27 01:39:35 +02:00
Norbi Peti e35e94e87c
Migrate chat formatting to Paper's text component API (#130)
- Also updated the configs to use the interfaces
- Also updated the fun component to use a list config
- The text component change adds Paper as a requirement for this plugin
2023-06-19 00:42:29 +02:00
Norbi Peti 51cf31713b
Start fixing errors related to player API changes
- The fancy chat API would be useful here, I don't want to update my old code
2023-06-09 01:25:09 +02:00
Norbi Peti 2242655c41
Merge branch 'hotfix/1.0.1'
# Conflicts:
#	src/main/java/buttondevteam/chat/components/towny/TownyComponent.java
2023-06-07 23:37:10 +02:00
Norbi Peti 522f29ba58
Update Chroma-Core to v2.0.0 2023-04-26 00:03:18 +02:00
Norbi Peti 10bf0e98df
Update Towny dependency and replace methods that were removed (#128) 2023-03-13 00:47:40 +01:00
Norbi Peti 6c1378f370
Update dependencies and fix tellRaw for 1.17+ 2021-12-30 21:19:22 +01:00
Norbi Peti 56b9296fbb
Merge pull request #126 from TBMCPlugins/dependabot/maven/org.apache.logging.log4j-log4j-core-2.17.0
Bump log4j-core from 2.13.2 to 2.17.0
2021-12-30 16:47:37 +01:00
dependabot[bot] 5c399a08ad
Bump log4j-core from 2.13.2 to 2.17.0
Bumps log4j-core from 2.13.2 to 2.17.0.

---
updated-dependencies:
- dependency-name: org.apache.logging.log4j:log4j-core
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
2021-12-18 18:20:48 +00:00
Norbi Peti 724858ac70
Fix tellRaw for 1.16.4/1.16.5 2021-01-18 17:18:35 +01:00
Norbi Peti 9a10dcd1fc
Fix plugin.yml 2020-10-31 18:24:52 +01:00
Norbi Peti dc6df53c96
Improve test coverage, preparations, fixes
Removed an unnnecessary bit of code from ChatFormatter
2020-10-29 20:31:38 +01:00
Norbi Peti 7646db4487
Fix player data plugin name, Spotbugs fixes
Also set the version
2020-10-28 00:28:15 +01:00
Norbi Peti 8e9989caee
Convert all configs 2020-10-26 19:56:22 +01:00
Norbi Peti 77b5a069c5
Merge pull request #123 from TBMCPlugins/dependabot/maven/junit-junit-4.13.1
Bump junit from 4.12 to 4.13.1
2020-10-25 02:00:58 +02:00
Norbi Peti c52a6873fe
Exception stuff and player data stuff 2020-10-25 01:18:36 +02:00
Norbi Peti c6ba0ec607
Create codeql-analysis.yml 2020-10-13 18:02:45 +02:00
dependabot[bot] 737016bf00
Bump junit from 4.12 to 4.13.1
Bumps [junit](https://github.com/junit-team/junit4) from 4.12 to 4.13.1.
- [Release notes](https://github.com/junit-team/junit4/releases)
- [Changelog](https://github.com/junit-team/junit4/blob/main/doc/ReleaseNotes4.12.md)
- [Commits](https://github.com/junit-team/junit4/compare/r4.12...r4.13.1)

Signed-off-by: dependabot[bot] <support@github.com>
2020-10-13 15:56:57 +00:00
Norbi Peti a63f2bb256
Greentext formatter, doc and stuff 2020-09-06 22:46:24 +02:00
Norbi Peti 59dbc78b52
Fix #122
It will have to be fixed again at a later date
2020-09-04 03:56:25 +02:00
Norbi Peti b483b7df0c
Fix /waitwhat and /me 2020-09-04 03:41:23 +02:00
Norbi Peti 4d4448fca1
Remove htmlcleaner and fix #117 2020-08-26 22:19:56 +02:00
Norbi Peti 02423153de
Merge pull request #119 from TBMCPlugins/dependabot/maven/org.apache.logging.log4j-log4j-core-2.13.2
Bump log4j-core from 2.8.1 to 2.13.2
2020-07-27 01:15:05 +02:00
Norbi Peti ce4f40c2c4
Fix /u ncolor (#118) 2020-07-25 14:17:11 +02:00
dependabot[bot] 372b2f49b3
Bump log4j-core from 2.8.1 to 2.13.2
Bumps log4j-core from 2.8.1 to 2.13.2.

Signed-off-by: dependabot[bot] <support@github.com>
2020-07-01 18:27:01 +00:00
Norbi Peti 7448eb7e3a
1.16 updates, fixes 2020-06-27 03:00:08 +02:00
Norbi Peti c688ec9243
Finally fix Towny errors for 1.12 - use the intended API everywhere 2020-04-08 01:10:49 +02:00
Norbi Peti e4b47efd3f
Fix case when the second section goes further when combining
And added a test for it
2020-04-07 23:08:48 +02:00
Norbi Peti 43525bd93c
Add missing backslash after "From X" and before "n" 2020-03-20 02:06:07 +01:00
Norbi Peti 052149bcb7
Add tabcompletes, fix some commands and help texts 2020-03-20 01:26:14 +01:00
Norbi Peti 5d8ae7fbd0
Command fixes, remove old preprocessor
Fixed command channels
/tpahere message removed
Made /me an actual command
Fixed some help texts
2020-03-15 03:09:00 +01:00
Norbi Peti f3ec9e7870
Merge branch 'dev'
# Conflicts:
#	.idea/ButtonChat.iml
2020-03-04 23:11:31 +01:00
Norbi Peti 03b91d2fdb Don't allow sending messages too fast
The player needs to wait the configured amount of milliseconds between messages
#115
2020-03-03 16:13:39 +01:00
Norbi Peti 661534b92d Update README.md 2020-03-02 12:40:16 +01:00
52 changed files with 972 additions and 1225 deletions

0
.idea/ButtonChat.iml Normal file
View file

View file

@ -7,17 +7,15 @@ before_install: | # Wget BuildTools and run if cached folder not found
# grep so that download counts don't appear in log files # grep so that download counts don't appear in log files
java -jar BuildTools.jar --rev 1.12.2 | grep -vE "[^/ ]*/[^/ ]*\s*KB\s*$" | grep -v "^\s*$" java -jar BuildTools.jar --rev 1.12.2 | grep -vE "[^/ ]*/[^/ ]*\s*KB\s*$" | grep -v "^\s*$"
fi fi
cp ci/settings.xml $HOME/.m2/
language: java language: java
jdk: jdk:
- oraclejdk8 - oraclejdk11
sudo: true sudo: true
dist: trusty # Needed for Java 8, although we might not need Java 8
deploy: deploy:
- provider: releases - provider: releases
api_key: api_key:
secure: "F5YiEuD6LyRENUDMCslcSl0O0dg4IDk+nNeb4X2VLYlmb8dW9beMuIgjH8efTMeaQ3D/ntIkN0Dtf2GKvpOduhwkSbAgw4WM028X60SY9f2hmpEO3LmM4T1tKoDlI1T3BmhYP4KeTKBYn+etV1mSPbT07vUybCm/vGzvr96yMZGNFEoKsWLaEu7dZfBFULj4tXOwrLh/KO6BsdAHvZcGKWNVupPq3YoUVT0dpGcUudf5cpn+aaqMwyd709zgMbyCuqf+c5Udps43q4EKvr9z7TWxFUkGTPVVAcUVygJsi2ytuyA8TLMPq/KhYe9htnkNUnizbqv/j49xww0gVaD7OJXENJ4hAUTV4sdn1DXG45JXW+dir3V7YzbRYn3M+eCuKB2O77SXRZBkxcGtTMtCmghP9/tcRAQlXDXnxu7oAnlUVp17g/+aFApvlzZEZVx2N+fkyEe7JrUFlRCixtHyrmTLWhyV0Px9p0FHJpvSSCL0S0UKVAT/sNHYHhD5gouK7owEomEbG58XCsRDH6Et7RuDksB98ekK8brZp6S7dNIS2CVuVx1vIkXC8PzUGcpJQoztvEYUE20Axahh5s8AkE9n/O9jzs9ajcfYaHhWzYeUZzHdHllOYF9l6VoCUitTk4Sl8eJifSq3GzI+T6wGMBepZHLpe230MvBIrqGZ+Vg=" secure: "F5YiEuD6LyRENUDMCslcSl0O0dg4IDk+nNeb4X2VLYlmb8dW9beMuIgjH8efTMeaQ3D/ntIkN0Dtf2GKvpOduhwkSbAgw4WM028X60SY9f2hmpEO3LmM4T1tKoDlI1T3BmhYP4KeTKBYn+etV1mSPbT07vUybCm/vGzvr96yMZGNFEoKsWLaEu7dZfBFULj4tXOwrLh/KO6BsdAHvZcGKWNVupPq3YoUVT0dpGcUudf5cpn+aaqMwyd709zgMbyCuqf+c5Udps43q4EKvr9z7TWxFUkGTPVVAcUVygJsi2ytuyA8TLMPq/KhYe9htnkNUnizbqv/j49xww0gVaD7OJXENJ4hAUTV4sdn1DXG45JXW+dir3V7YzbRYn3M+eCuKB2O77SXRZBkxcGtTMtCmghP9/tcRAQlXDXnxu7oAnlUVp17g/+aFApvlzZEZVx2N+fkyEe7JrUFlRCixtHyrmTLWhyV0Px9p0FHJpvSSCL0S0UKVAT/sNHYHhD5gouK7owEomEbG58XCsRDH6Et7RuDksB98ekK8brZp6S7dNIS2CVuVx1vIkXC8PzUGcpJQoztvEYUE20Axahh5s8AkE9n/O9jzs9ajcfYaHhWzYeUZzHdHllOYF9l6VoCUitTk4Sl8eJifSq3GzI+T6wGMBepZHLpe230MvBIrqGZ+Vg="
file: 'Chroma-Core/target/Chroma-Core.jar' file: 'target/Chroma-Chat.jar'
on: on:
tags: true tags: true
skip_cleanup: true skip_cleanup: true

143
README.md
View file

@ -1,133 +1,28 @@
# The Button Minecraft server chat plugin # Chroma-Chat plugin
A plugin that provides markdown formatting, name mentioning and other chat features.
## How to use ## Components
### Players
#### Obtaining the flair (/u accept)
At first, you need to connect your Reddit account with your Minecraft account. This is done by writing your Minecraft name to [this thread](https://www.reddit.com/r/Chromagamers/comments/51ys94/flair_thread_for_the_mc_server/), following the instructions in the post.
When you're done, connect to the server, if you aren't already on. You should see a message after a while (max. 10 seconds) asking if you're the correct Reddit user. Type /u accept to confirm it and accept your flair. ### Announcer
This component simply sends messages globally based on a configurable list in a given interval.
__Note__: You can comment your ingame name from multiple Reddit accounts. In this case, you'll need to specify the exact username you want to pair with your Minecraft account. For example: ### Append text
This component allows the players to put tableflips and other texts after their messages using /tableflip and other commands.
/u accept NorbiPeti ### Chat-only
This component lets a player become invincible at the cost of not being able to move. It was made for chat clients.
#### Hiding the message (/u ignore) ### Flair
You can use this command to hide the notice showing up after you log in if you don't have a flair accepted. This component downloads /r/TheButton flairs from Reddit for users who comment in a specific thread. This was the original function of the plugin.
#### Flair not showing up ### Formatter
Please note that in some cases your flair cannot be obtained (specifically, if it's not stored by karmadecay.com, in which case possibly Karmancer can't show it as well). In this case, there are two possibilities. This component provides the Markdown and other formatting and name mentioning.
If you're a non-presser or a can't press and only your time is recorded, it will automatically decide based on your account creation date. ### Fun
This component has some random things I added for fun, including "Press F to pay respects" and rainbow chat.
If nothing is known about your flair, you need to ask an admin to set the flair for you. Please prepare a link to a comment you made on /r/thebutton, if possible. ### Town colors
This component allows mayors and kings to set a color for their town/nation, which sets each resident's name colors and also shows on Dynmap.
#### Getting someone's Reddit username (/u name) ### Towny
You can see a player's username if they have a flair shown. This component is needed by the town colors component. Besides, it reads Towny events to be broadcasted to Discord, if that plugin is used.
#### Name mentioning
If you simply say any online player's full playername or nickname, it'll highlight it and play a sound for the target player.
If you say a nickname, it'll show it's original colors, if you say a username, then it will choose based on flair color if known, otherwise it'll use the aqua color.
You can also use @console to ping the console. If someone is there, they'll receive an audible bell signal.
#### RP/OOC mode (/nrp or /ooc)
You can use /ooc <message> to say something Out-of-Character. Otherwise everything you speak should be treated as said in RP, except when it is obvious it's not in RP (like talking about the server).
#### Greentext support (>message)
Start your message with '>' to make it green.
#### Hashtags (#hashtag)
If you say a hashtag in global chat, it'll highlight it and makes it clickable, linking to the hashtag page on Twitter.
#### Paying respects (F)
If a player dies, sometimes the plugin will tell everyone "Press F to pay respects.". After a few seconds, a message will tell everyone how many people paid their respects.
If you hover over a player's name in chat, you can see how much respect they gained this way, divided by the number of eligible deaths.
#### Copy messages
To copy a message from chat, click the channel identifier (for example: [g] or [TC]) at the beginning of the message.
#### Tableflipping (/tableflip and /unflip) and shrug (/shrug)
The idea of this command came from Discord.
Examples:
/tableflip - (╯°□°)╯︵ ┻━┻
/tableflip test - test(╯°□°)╯︵ ┻━┻
/unflip - ┬─┬ ( ゜-゜ノ)
/unflip test - test┬─┬ ( ゜-゜ノ)
#### Chat only (/chatonly)
You can use this mode to protect yourself if you connect from a chat-only client. This will make you invincible, but unable to move, teleport or interact with the world in any way.
#### Rainbow chat (/u c)
Chat in rainbow/Presser colors.
### Admins
Type /u admin for a list of the commands.
#### Seeing player information (/u admin playerinfo)
You can check someone's flair status and other infos in case something goes wrong.
It outputs the player name (useful if something goes *really* wrong), the player's current ingame flair, the Reddit username, and their flair status:
* Accepted: The user has a flair shown after their name.
* Ignored: The user chose to hide their flair, but they have one.
* Recognised: The user has recognised flair(s) but haven't accepted any.
* Commented: The user commented, but their flair isn't known.
* NoComment: The user haven't commented in the thread.
#### Reloading the plugin (/u admin reload)
This is useful if you want to change a file related to the plugin.
Be careful and make sure you do /u admin save before you reload the plugin. You need to confirm your action (/u admin confirm) to make sure no setting is lost.
If you want to edit a file, you need to do /u admin save, then edit the file you want, then do /u admin reload.
#### Setting the flair by hand (/u admin setflair)
This allows you to set any flair you want to any player. This will override the automatic flairs, though it's not recommended to do so. However, the player can reset the automatic flair at any time (see /u accept).
* To remove a user's flair:
/u admin setflair <playername> none false
* To set a non-presser or can't press flair:
/u admin setflair <playername> non-presser/cant-press false
* To set a cheater flair:
/u admin setflair <playername> <time> true
* To also set the username for the flair:
/u admin setflair <playername> <time> <cheater> <username>
Usage:
/u admin setflair <playername> <time (without s) or non-presser, can't press, none> <cheater (true/false)>> [username]
#### Updating the plugin (/u admin updateplugin)
I've made a simple command to allow updating the plugin easily. After running this command, the server needs to get restarted for the changes to take effect.
This command will not do any other thing than downloading the JAR file from here to the plugins directory. Do not spam it, because it will then generate unnecessary network traffic on the server.
#### Toggle settings
/u admin togglerpshow - Toggles [RP] tag shown at each message except /ooc or /nrp.
/u admin debug - Toggles debug mode. Currently it outputs a lot of info about the chat formatting.
#### Setting the sound played on name mentioning
You can set the sound played by editing "notificationsound" and "notificationpitch" in the config file (thebuttonmc.yml).
#### Announcements (/u announce)
You can make announcements broadcasted every n minutes where you can set n and it defaults to 15.
/u announce add <message> - Adds a new announcement. It supports formatting codes with &.
/u announce remove <index> - Remove announcement by index (see below).
/u announce list - List announcements with indexes.
/u announce settime <minutes> - Set the time between announcements in minutes.
/u announce edit <index> <message> - Directly edits the announcement at the specified index. If there are less announcements than index, it'll create enough announcements.
#### Color modes (/u c)
Use /u c \<colorname\> to set the color of your messages.

View file

@ -1,36 +0,0 @@
<settings xmlns="http://maven.apache.org/SETTINGS/1.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/SETTINGS/1.0.0
http://maven.apache.org/xsd/settings-1.0.0.xsd">
<activeProfiles>
<activeProfile>github</activeProfile>
</activeProfiles>
<profiles>
<profile>
<id>github</id>
<repositories>
<!-- <repository>
<id>central</id>
<url>https://repo1.maven.org/maven2</url>
<releases><enabled>true</enabled></releases>
<snapshots><enabled>false</enabled></snapshots>
</repository> -->
<repository>
<id>github</id>
<name>GitHub Towny Apache Maven Packages</name>
<url>https://maven.pkg.github.com/TownyAdvanced/Towny</url>
</repository>
</repositories>
</profile>
</profiles>
<servers>
<server>
<id>github</id>
<username>NorbiPeti</username>
<password>${env.GHTOKEN}</password>
</server>
</servers>
</settings>

280
pom.xml
View file

@ -1,56 +1,30 @@
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion> <modelVersion>4.0.0</modelVersion>
<parent> <parent>
<groupId>com.github.TBMCPlugins.ChromaCore</groupId> <groupId>com.github.TBMCPlugins.ChromaCore</groupId>
<artifactId>CorePOM</artifactId> <artifactId>CorePOM</artifactId>
<version>master-SNAPSHOT</version> <version>master-SNAPSHOT</version>
</parent> </parent>
<version>0.0.1-SNAPSHOT</version> <version>v${noprefix.version}-SNAPSHOT</version>
<name>Chroma-Chat Plugin</name> <name>Chroma-Chat Plugin</name>
<description>Chroma-Chat Plugin</description> <description>Chroma-Chat Plugin</description>
<build> <build>
<sourceDirectory>src/main/java</sourceDirectory> <sourceDirectory>src/main/java</sourceDirectory>
<resources> <resources>
<resource> <resource>
<directory>src</directory> <directory>src/main/resources</directory>
<excludes> <includes>
<exclude>**/*.java</exclude> <include>*.properties</include>
</excludes> <include>*.yml</include>
</resource> <include>*.csv</include>
<resource> <include>*.txt</include>
<directory>src/main/resources</directory> </includes>
<includes> <filtering>true</filtering>
<include>*.properties</include>
<include>*.yml</include>
<include>*.csv</include>
<include>*.txt</include>
</includes>
<filtering>true</filtering>
</resource> </resource>
</resources> </resources>
<finalName>Chroma-Chat</finalName> <finalName>Chroma-Chat</finalName>
<plugins> <plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-shade-plugin</artifactId>
<version>3.2.1</version>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>shade</goal>
</goals>
<configuration>
<artifactSet>
<includes>
<include>net.sourceforge.htmlcleaner:htmlcleaner</include>
</includes>
</artifactSet>
</configuration>
</execution>
</executions>
</plugin>
<plugin> <plugin>
<groupId>org.apache.maven.plugins</groupId> <groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-resources-plugin</artifactId> <artifactId>maven-resources-plugin</artifactId>
@ -92,64 +66,6 @@
</useSystemClassLoader> <!-- https://stackoverflow.com/a/53012553/2703239 --> </useSystemClassLoader> <!-- https://stackoverflow.com/a/53012553/2703239 -->
</configuration> </configuration>
</plugin> </plugin>
<!-- <plugin>
<groupId>pl.project13.maven</groupId>
<artifactId>git-commit-id-plugin</artifactId>
<version>2.2.5</version>
<executions>
<execution>
<id>get-the-git-infos</id>
<goals>
<goal>revision</goal>
</goals>
*NOTE*: The default phase of revision is initialize, but in case you want to change it, you can do so by adding the phase here
<phase>initialize</phase>
<configuration>
<injectAllReactorProjects>true</injectAllReactorProjects>
</configuration>
</execution>
<execution>
<id>validate-the-git-infos</id>
<goals>
<goal>validateRevision</goal>
</goals>
*NOTE*: The default phase of validateRevision is verify, but in case you want to change it, you can do so by adding the phase here
<phase>package</phase>
<configuration>
<validationProperties>
- <validationProperty>
<name>validating git dirty</name>
<value>${git.branch}</value>
<shouldMatchTo>dev</shouldMatchTo>
</validationProperty> -
</validationProperties>
</configuration>
</execution>
</executions>
<configuration>
<injectAllReactorProjects>true</injectAllReactorProjects>
<verbose>true</verbose>
<dotGitDirectory>${project.basedir}/.git</dotGitDirectory>
</configuration>
</plugin> -->
<!-- <plugin> <groupId>org.basepom.maven</groupId> <artifactId>duplicate-finder-maven-plugin</artifactId>
<version>1.2.1</version> <executions> <execution> <goals> <goal>check</goal>
</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>
@ -164,110 +80,121 @@
</repository> </repository>
<repository> <repository>
<id>ess-repo</id> <id>ess-repo</id>
<url>https://ci.ender.zone/plugin/repository/everything/</url> <url>https://repo.essentialsx.net/releases/</url>
</repository> </repository>
<!-- <repository> <!-- <repository>
<id>Minigames</id> <id>Minigames</id>
<url>http://maven.addstar.com.au/artifactory/release</url> <url>http://maven.addstar.com.au/artifactory/release</url>
</repository> --> </repository> -->
<!-- <repository> <!-- <repository>
<id>vault-repo</id> <id>vault-repo</id>
<url>http://nexus.hc.to/content/repositories/pub_releases</url> <url>http://nexus.hc.to/content/repositories/pub_releases</url>
</repository> --> </repository> -->
<!-- <repository> <id>WorldEdit</id> <url>http://maven.sk89q.com/artifactory/repo</url> <!-- <repository> <id>WorldEdit</id> <url>http://maven.sk89q.com/artifactory/repo</url>
</repository> --> </repository> -->
<repository> <repository>
<id>projectlombok.org</id> <id>projectlombok.org</id>
<url>http://projectlombok.org/mavenrepo</url> <url>https://projectlombok.org/mavenrepo</url>
</repository> </repository>
<repository>
<id>Dynmap</id>
<url>https://repo.mikeprimm.com</url>
</repository>
<repository>
<id>papermc</id>
<url>https://repo.papermc.io/repository/maven-public/</url>
</repository>
</repositories> </repositories>
<dependencies> <dependencies>
<dependency> <dependency> <!-- TODO: Can't update MockBukkit because of a ByteBuddy exception and the old version relies on 1.19.1 -->
<groupId>org.spigotmc</groupId> <groupId>io.papermc.paper</groupId>
<artifactId>spigot-api</artifactId> <artifactId>paper-api</artifactId>
<version>1.12.2-R0.1-SNAPSHOT</version> <version>1.19.1-R0.1-SNAPSHOT</version>
</dependency> <scope>provided</scope>
<dependency> </dependency>
<groupId>com.github.TBMCPlugins.ChromaCore</groupId>
<artifactId>Chroma-Core</artifactId>
<version>${branch}-SNAPSHOT</version>
</dependency>
<!-- https://mvnrepository.com/artifact/net.sourceforge.htmlcleaner/htmlcleaner -->
<dependency>
<groupId>net.sourceforge.htmlcleaner</groupId>
<artifactId>htmlcleaner</artifactId>
<version>2.16</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.reflections/reflections -->
<dependency>
<groupId>org.reflections</groupId>
<artifactId>reflections</artifactId>
<version>0.9.10</version>
</dependency>
<dependency> <dependency>
<groupId>net.ess3</groupId> <groupId>com.github.TBMCPlugins.ChromaCore</groupId>
<artifactId>Chroma-Core</artifactId>
<version>v2.0.0-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>net.essentialsx</groupId>
<artifactId>EssentialsX</artifactId> <artifactId>EssentialsX</artifactId>
<version>2.17.1</version> <version>2.19.2</version>
<scope>provided</scope> <scope>provided</scope>
</dependency> </dependency>
<dependency> <dependency>
<groupId>com.palmergames.bukkit.towny</groupId> <groupId>com.github.TownyAdvanced</groupId>
<artifactId>Towny</artifactId> <artifactId>Towny</artifactId>
<version>0.95.2.0</version> <!-- <version>8d3b6b6</version> ButtonCore repo -->
<version>0.98.6.0</version>
<scope>provided</scope>
</dependency>
<!-- <dependency> <groupId>au.com.mineauz</groupId> <artifactId>Minigames</artifactId>
<version>1.8.0</version> </dependency> -->
<dependency>
<groupId>com.github.MilkBowl</groupId>
<artifactId>VaultAPI</artifactId>
<version>1.7</version>
<scope>provided</scope> <scope>provided</scope>
</dependency> </dependency>
<!-- <dependency> <groupId>au.com.mineauz</groupId> <artifactId>Minigames</artifactId>
<version>1.8.0</version> </dependency> -->
<dependency>
<groupId>com.github.milkbowl</groupId>
<artifactId>VaultAPI</artifactId>
<version>master-SNAPSHOT</version>
<scope>provided</scope>
</dependency>
<!-- https://mvnrepository.com/artifact/org.projectlombok/lombok --> <!-- https://mvnrepository.com/artifact/org.projectlombok/lombok -->
<dependency> <dependency>
<groupId>org.projectlombok</groupId> <groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId> <artifactId>lombok</artifactId>
<version>1.18.10</version> <version>1.18.22</version>
<scope>provided</scope> <scope>provided</scope>
</dependency> </dependency>
<dependency>
<groupId>org.spigotmc</groupId>
<artifactId>spigot</artifactId>
<version>1.12.2-R0.1-SNAPSHOT</version>
<scope>provided</scope>
</dependency>
<!-- <dependency> <!-- <dependency>
<groupId>org.spigotmc</groupId> <groupId>org.spigotmc</groupId>
<artifactId>spigot</artifactId> <artifactId>spigot</artifactId>
<version>1.14.4-R0.1-SNAPSHOT</version> <version>1.16.4-R0.1-SNAPSHOT</version>
<scope>provided</scope>
</dependency> --> </dependency> -->
<dependency> <dependency>
<groupId>com.github.webbukkit</groupId> <groupId>com.github.TownyAdvanced</groupId>
<artifactId>Dynmap-Towny</artifactId> <artifactId>Dynmap-Towny</artifactId>
<version>master-SNAPSHOT</version> <version>0.89</version>
</dependency>
<dependency>
<groupId>com.github.webbukkit</groupId>
<artifactId>Dynmap</artifactId>
<version>v2.5</version>
</dependency> </dependency>
<dependency>
<groupId>us.dynmap</groupId>
<artifactId>dynmap-api</artifactId>
<version>3.2-beta-1</version>
</dependency>
<!-- https://mvnrepository.com/artifact/junit/junit --> <!-- https://mvnrepository.com/artifact/junit/junit -->
<dependency> <dependency>
<groupId>junit</groupId> <groupId>junit</groupId>
<artifactId>junit</artifactId> <artifactId>junit</artifactId>
<version>4.12</version> <version>4.13.2</version>
<scope>test</scope> <scope>test</scope>
</dependency> </dependency>
<!-- Included in vanilla minecraft's JAR --> <!-- Included in vanilla minecraft's JAR -->
<dependency> <dependency>
<groupId>org.apache.logging.log4j</groupId> <groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-core</artifactId> <artifactId>log4j-core</artifactId>
<version>2.8.1</version> <version>2.17.0</version>
<scope>provided</scope> <scope>provided</scope>
</dependency> </dependency>
<!-- TestPrepare also needs it (ChromaCore) so the versions should match -->
<dependency>
<groupId>org.mockito</groupId>
<artifactId>mockito-core</artifactId>
<version>4.2.0</version>
<scope>test</scope>
</dependency>
<!-- https://mvnrepository.com/artifact/com.mojang/brigadier -->
<dependency>
<groupId>com.mojang</groupId>
<artifactId>brigadier</artifactId>
<version>1.0.500</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>com.github.seeseemelk</groupId>
<artifactId>MockBukkit-v1.19</artifactId>
<version>2.29.0</version>
<scope>test</scope>
</dependency>
</dependencies> </dependencies>
<artifactId>Chroma-Chat</artifactId> <artifactId>Chroma-Chat</artifactId>
<organization> <organization>
@ -278,23 +205,6 @@
<!-- github server corresponds to entry in ~/.m2/settings.xml --> <!-- github server corresponds to entry in ~/.m2/settings.xml -->
<github.global.server>githubo</github.global.server> <github.global.server>githubo</github.global.server>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<branch> <noprefix.version>1.0.0</noprefix.version>
master
</branch> <!-- Should be master if building ButtonCore locally - the CI will overwrite it (see below) -->
</properties> </properties>
<profiles>
<profile>
<id>ci</id>
<activation>
<property>
<name>env.TRAVIS_BRANCH</name>
</property>
</activation>
<properties>
<!-- Override only if necessary -->
<branch>${env.TRAVIS_BRANCH}</branch>
</properties>
</profile>
</profiles>
</project> </project>

View file

@ -1,56 +1,41 @@
package buttondevteam.chat; package buttondevteam.chat;
import buttondevteam.chat.components.flair.FlairStates; import buttondevteam.chat.components.flair.FlairStates;
import buttondevteam.lib.architecture.config.IConfigData;
import buttondevteam.lib.architecture.config.IListConfigData;
import buttondevteam.lib.chat.Color; import buttondevteam.lib.chat.Color;
import buttondevteam.lib.player.EnumPlayerData;
import buttondevteam.lib.player.PlayerClass; import buttondevteam.lib.player.PlayerClass;
import buttondevteam.lib.player.PlayerData;
import buttondevteam.lib.player.TBMCPlayerBase; import buttondevteam.lib.player.TBMCPlayerBase;
import org.bukkit.Bukkit; import org.bukkit.Bukkit;
import org.bukkit.entity.Player; import org.bukkit.entity.Player;
import java.util.ArrayList; import java.util.Collections;
import java.util.List;
@PlayerClass(pluginname = "Button1Chat") @PlayerClass(pluginname = "Chroma-Chat")
public class ChatPlayer extends TBMCPlayerBase { public class ChatPlayer extends TBMCPlayerBase {
public PlayerData<String> UserName() { public final IConfigData<String> UserName = getConfig().getData("UserName", "");
return data(null);
}
public List<String> UserNames() { public final IListConfigData<String> UserNames = getConfig().getListData("UserNames", Collections.emptyList());
return data(new ArrayList<String>()).get();
}
public PlayerData<Integer> FlairTime() { public final IConfigData<Integer> FlairTime = getConfig().getData("FlairTime", FlairTimeNone);
return data(FlairTimeNone);
}
public EnumPlayerData<FlairStates> FlairState() { public final IConfigData<FlairStates> FlairState = getConfig().getData("FlairState", FlairStates.NoComment,
return dataEnum(FlairStates.class, FlairStates.NoComment); fs -> FlairStates.valueOf((String) fs), FlairStates::toString);
}
public PlayerData<Integer> FCount() { public final IConfigData<Integer> FCount = getConfig().getData("FCount", 0);
return data(0);
}
public PlayerData<Integer> FDeaths() { public final IConfigData<Integer> FDeaths = getConfig().getData("FDeaths", 0);
return data(0);
}
public PlayerData<Boolean> FlairCheater() { public final IConfigData<Boolean> FlairCheater = getConfig().getData("FlairCheater", false);
return data(false);
}
public PlayerData<ArrayList<Integer>> NameColorLocations() { // No byte[], no TIntArrayList public final IListConfigData<Integer> NameColorLocations = getConfig().getListData("NameColorLocations", Collections.emptyList()); // No byte[], no TIntArrayList
return data(null);
}
public boolean Working; public boolean Working;
// public int Tables = 10; // public int Tables = 10;
public boolean RainbowPresserColorMode = false; public boolean RainbowPresserColorMode = false;
public Color OtherColorMode = null; public Color OtherColorMode = null;
public boolean ChatOnly = false; public boolean ChatOnly = false;
public long LastMessageTime = 0L;
public static final int FlairTimeNonPresser = -1; public static final int FlairTimeNonPresser = -1;
public static final int FlairTimeCantPress = -2; public static final int FlairTimeCantPress = -2;
@ -58,13 +43,12 @@ public class ChatPlayer extends TBMCPlayerBase {
/** /**
* Gets the player's flair, optionally formatting for Minecraft. * Gets the player's flair, optionally formatting for Minecraft.
* *
* @param noformats * @param noformats The MC formatting codes will be only applied if false
* The MC formatting codes will be only applied if false
* @return The flair * @return The flair
*/ */
public String GetFormattedFlair(boolean noformats) { public String GetFormattedFlair(boolean noformats) {
int time = FlairTime().get(); int time = FlairTime.get();
if (time == FlairTimeCantPress) if (time == FlairTimeCantPress)
return noformats ? "(can't press)" : "§r(--s)§r"; return noformats ? "(can't press)" : "§r(--s)§r";
if (time == FlairTimeNonPresser) if (time == FlairTimeNonPresser)
@ -76,7 +60,7 @@ public class ChatPlayer extends TBMCPlayerBase {
/** /**
* Gets the player's flair, formatted for Minecraft. * Gets the player's flair, formatted for Minecraft.
* *
* @return The flair * @return The flair
*/ */
public String GetFormattedFlair() { public String GetFormattedFlair() {
@ -84,13 +68,13 @@ public class ChatPlayer extends TBMCPlayerBase {
} }
public void SetFlair(int time) { public void SetFlair(int time) {
FlairTime().set(time); FlairTime.set(time);
FlairUpdate(); FlairUpdate();
} }
public void SetFlair(int time, boolean cheater) { public void SetFlair(int time, boolean cheater) {
FlairTime().set(time); FlairTime.set(time);
FlairCheater().set(cheater); FlairCheater.set(cheater);
FlairUpdate(); FlairUpdate();
} }
@ -98,15 +82,15 @@ public class ChatPlayer extends TBMCPlayerBase {
// Flairs from Command Block The Button - Teams // Flairs from Command Block The Button - Teams
// PluginMain.Instance.getServer().getScoreboardManager().getMainScoreboard().getTeams().add() // PluginMain.Instance.getServer().getScoreboardManager().getMainScoreboard().getTeams().add()
Player p = Bukkit.getPlayer(uuid); Player p = Bukkit.getPlayer(getUniqueId());
if (p != null) if (p != null)
p.setPlayerListName(String.format("%s%s", p.getDisplayName(), GetFormattedFlair())); p.setPlayerListName(String.format("%s%s", p.getDisplayName(), GetFormattedFlair()));
} }
public short GetFlairColor() { public short GetFlairColor() {
if (FlairCheater().get()) if (FlairCheater.get())
return 0x5; return 0x5;
final int flairTime = FlairTime().get(); final int flairTime = FlairTime.get();
if (flairTime == FlairTimeNonPresser) if (flairTime == FlairTimeNonPresser)
return 0x7; return 0x7;
else if (flairTime == FlairTimeCantPress) else if (flairTime == FlairTimeCantPress)
@ -127,6 +111,6 @@ public class ChatPlayer extends TBMCPlayerBase {
} }
public double getF() { public double getF() {
return (double) FCount().get() / (double) FDeaths().get(); return (double) FCount.get() / (double) FDeaths.get();
} }
} }

View file

@ -1,12 +1,13 @@
package buttondevteam.chat; package buttondevteam.chat;
import buttondevteam.lib.ChromaUtils; import buttondevteam.core.component.channel.Channel;
import buttondevteam.lib.TBMCChatEvent; import buttondevteam.lib.TBMCChatEvent;
import buttondevteam.lib.player.ChromaGamerBase;
import org.bukkit.Bukkit; import org.bukkit.Bukkit;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player; import org.bukkit.entity.Player;
import java.util.Optional; import java.util.Optional;
import java.util.function.Function;
public final class ChatUtils { public final class ChatUtils {
public static final String MCORIGIN = "Minecraft"; //Shouldn't change, like ever - TBMCPlayer.getFolderForType(TBMCPlayer.class) capitalized public static final String MCORIGIN = "Minecraft"; //Shouldn't change, like ever - TBMCPlayer.getFolderForType(TBMCPlayer.class) capitalized
@ -44,16 +45,21 @@ public final class ChatUtils {
/** /**
* Sends a regular (non-Markdown) chat message. Used as a fallback if the chat processing fails. * Sends a regular (non-Markdown) chat message. Used as a fallback if the chat processing fails.
* *
* @param e The chat event * @param e The chat event
* @param modifier A function that alters the message to be displayed to the player
*/ */
public static void sendChatMessage(TBMCChatEvent e, Function<String, String> modifier) { public static void sendChatMessage(TBMCChatEvent e) {
var str = "[" + e.getChannel().DisplayName().get() + "] <" var str = getMessageString(e.getChannel(), e.getUser(), e.getMessage());
+ ChromaUtils.getDisplayName(e.getSender()) + "> " + e.getMessage();
str = modifier.apply(str);
for (Player p : Bukkit.getOnlinePlayers()) for (Player p : Bukkit.getOnlinePlayers())
if (e.shouldSendTo(p)) if (e.shouldSendTo(ChromaGamerBase.getFromSender(p)))
p.sendMessage(str); p.sendMessage(str);
Bukkit.getConsoleSender().sendMessage(str); Bukkit.getConsoleSender().sendMessage(str);
} }
public static String getMessageString(Channel channel, ChromaGamerBase sender, String message) {
return "§c!§r[" + channel.displayName.get() + "] <" + sender.getName() + "> " + message;
}
public static void sendChatMessage(Channel channel, ChromaGamerBase sender, String message, CommandSender to) {
to.sendMessage(getMessageString(channel, sender, message));
}
} }

View file

@ -1,6 +1,7 @@
package buttondevteam.chat; package buttondevteam.chat;
import buttondevteam.chat.commands.MWikiCommand; import buttondevteam.chat.commands.MWikiCommand;
import buttondevteam.chat.commands.MeCommand;
import buttondevteam.chat.commands.SnapCommand; import buttondevteam.chat.commands.SnapCommand;
import buttondevteam.chat.commands.ucmds.HelpCommand; import buttondevteam.chat.commands.ucmds.HelpCommand;
import buttondevteam.chat.commands.ucmds.HistoryCommand; import buttondevteam.chat.commands.ucmds.HistoryCommand;
@ -20,19 +21,16 @@ import buttondevteam.core.component.channel.Channel;
import buttondevteam.lib.TBMCCoreAPI; import buttondevteam.lib.TBMCCoreAPI;
import buttondevteam.lib.architecture.ButtonPlugin; import buttondevteam.lib.architecture.ButtonPlugin;
import buttondevteam.lib.architecture.Component; import buttondevteam.lib.architecture.Component;
import buttondevteam.lib.architecture.ConfigData; import buttondevteam.lib.architecture.config.IConfigData;
import buttondevteam.lib.chat.Color; import buttondevteam.lib.chat.Color;
import buttondevteam.lib.chat.TBMCChatAPI; import buttondevteam.lib.chat.TBMCChatAPI;
import com.earth2me.essentials.Essentials; import com.earth2me.essentials.Essentials;
import net.milkbowl.vault.economy.Economy;
import net.milkbowl.vault.permission.Permission; import net.milkbowl.vault.permission.Permission;
import org.bukkit.Bukkit; import org.bukkit.Bukkit;
import org.bukkit.command.ConsoleCommandSender; import org.bukkit.command.ConsoleCommandSender;
import org.bukkit.plugin.RegisteredServiceProvider; import org.bukkit.plugin.RegisteredServiceProvider;
public class PluginMain extends ButtonPlugin { // Translated to Java: 2015.07.15. public class PluginMain extends ButtonPlugin { // Translated to Java: 2015.07.15.
// A user, which flair isn't obtainable:
// https://www.reddit.com/r/thebutton/comments/31c32v/i_pressed_the_button_without_really_thinking/
public static PluginMain Instance; public static PluginMain Instance;
public static ConsoleCommandSender Console; public static ConsoleCommandSender Console;
@ -40,9 +38,7 @@ public class PluginMain extends ButtonPlugin { // Translated to Java: 2015.07.15
* If enabled, stores and displays the last 10 messages the player can see (public, their town chat etc.) * 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. * 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<Boolean> storeChatHistory() { public IConfigData<Boolean> storeChatHistory = getIConfig().getData("storeChatHistory", true);
return getIConfig().getData("storeChatHistory", true);
}
// Fired when plugin is first enabled // Fired when plugin is first enabled
@Override @Override
@ -57,10 +53,10 @@ public class PluginMain extends ButtonPlugin { // Translated to Java: 2015.07.15
if (Bukkit.getPluginManager().isPluginEnabled("Towny")) if (Bukkit.getPluginManager().isPluginEnabled("Towny"))
Component.registerComponent(this, new TownyComponent()); Component.registerComponent(this, new TownyComponent());
TBMCChatAPI.RegisterChatChannel(new Channel("§7RP§f", Color.Gray, "rp", null)); //Since it's null, it's recognised as global TBMCChatAPI.registerChatChannel(new Channel("§7RP§f", Color.Gray, "rp", null)); //Since it's null, it's recognised as global
if (!setupEconomy() || !setupPermissions()) if (!setupPermissions())
TBMCCoreAPI.SendException("We're in trouble", new Exception("Failed to set up economy or permissions!")); TBMCCoreAPI.SendException("We're in trouble", new Exception("Failed to set up permissions!"), this);
if (Bukkit.getPluginManager().isPluginEnabled("Towny")) if (Bukkit.getPluginManager().isPluginEnabled("Towny"))
Component.registerComponent(this, new TownColorComponent()); Component.registerComponent(this, new TownColorComponent());
@ -76,6 +72,7 @@ public class PluginMain extends ButtonPlugin { // Translated to Java: 2015.07.15
registerCommand(new MWikiCommand()); registerCommand(new MWikiCommand());
registerCommand(new ReloadCommand()); registerCommand(new ReloadCommand());
registerCommand(new SnapCommand()); registerCommand(new SnapCommand());
registerCommand(new MeCommand());
} }
public static Essentials essentials = null; public static Essentials essentials = null;
@ -86,7 +83,6 @@ public class PluginMain extends ButtonPlugin { // Translated to Java: 2015.07.15
} }
public static Permission permission = null; public static Permission permission = null;
public static Economy economy = null;
private boolean setupPermissions() { private boolean setupPermissions() {
RegisteredServiceProvider<Permission> permissionProvider = getServer().getServicesManager() RegisteredServiceProvider<Permission> permissionProvider = getServer().getServicesManager()
@ -97,14 +93,4 @@ public class PluginMain extends ButtonPlugin { // Translated to Java: 2015.07.15
return (permission != null); return (permission != null);
} }
private boolean setupEconomy() {
RegisteredServiceProvider<Economy> economyProvider = getServer().getServicesManager()
.getRegistration(net.milkbowl.vault.economy.Economy.class);
if (economyProvider != null) {
economy = economyProvider.getProvider();
}
return (economy != null);
}
} }

View file

@ -2,10 +2,14 @@ package buttondevteam.chat;
import buttondevteam.core.MainPlugin; import buttondevteam.core.MainPlugin;
import buttondevteam.lib.TBMCChatEvent; import buttondevteam.lib.TBMCChatEvent;
import buttondevteam.lib.player.ChromaGamerBase;
import lombok.experimental.UtilityClass; import lombok.experimental.UtilityClass;
import lombok.val; import lombok.val;
import org.bukkit.entity.Player; import org.bukkit.entity.Player;
import java.lang.reflect.Array;
import java.lang.reflect.Method;
import java.util.UUID;
import java.util.function.BiPredicate; import java.util.function.BiPredicate;
import java.util.function.Predicate; import java.util.function.Predicate;
@ -13,14 +17,12 @@ import java.util.function.Predicate;
public class VanillaUtils { public class VanillaUtils {
public String getGroupIfChatOn(Player p, TBMCChatEvent e) { public String getGroupIfChatOn(Player p, TBMCChatEvent e) {
try { try {
if (isChatOn(p)) // Only send if client allows chat if (!isChatOn(p)) // Only send if client allows chat
return e.getGroupID(p);
else
return null; return null;
} catch (NoClassDefFoundError ex) { } catch (NoClassDefFoundError ex) {
MainPlugin.Instance.getLogger().warning("Compatibility error, can't check if the chat is hidden by the player."); MainPlugin.getInstance().getLogger().warning("Compatibility error, can't check if the chat is hidden by the player.");
return e.getGroupID(p);
} }
return e.getGroupID(ChromaGamerBase.getFromSender(p));
} }
private Predicate<Player> isChatOn; private Predicate<Player> isChatOn;
@ -79,9 +81,22 @@ public class VanillaUtils {
if (notCraftPlayer(pcl)) return false; if (notCraftPlayer(pcl)) return false;
val hm = pcl.getMethod("getHandle"); val hm = pcl.getMethod("getHandle");
val handle = hm.invoke(p); val handle = hm.invoke(p);
val nms = handle.getClass().getPackage().getName(); var nmsOrChat = handle.getClass().getPackage().getName();
val chatcompcl = Class.forName(nms + ".IChatBaseComponent"); if (!nmsOrChat.contains(".v1_"))
val sendmsg = handle.getClass().getMethod("sendMessage", chatcompcl); nmsOrChat = "net.minecraft.network.chat";
val chatcompcl = Class.forName(nmsOrChat + ".IChatBaseComponent");
//val chatcomarrcl = Class.forName("[L" + chatcompcl.getName() + ";");
val chatcomparr = Array.newInstance(chatcompcl, 1);
final Method sendmsg;
{
Method sendmsg1;
try {
sendmsg1 = handle.getClass().getMethod("sendMessage", UUID.class, chatcomparr.getClass());
} catch (NoSuchMethodException e) {
sendmsg1 = handle.getClass().getMethod("sendMessage", chatcomparr.getClass());
}
sendmsg = sendmsg1;
}
/*val ccucl = Class.forName(nms + ".ChatComponentUtils"); /*val ccucl = Class.forName(nms + ".ChatComponentUtils");
val iclcl = Class.forName(nms + ".ICommandListener"); val iclcl = Class.forName(nms + ".ICommandListener");
@ -97,7 +112,11 @@ public class VanillaUtils {
val hhandle = hm.invoke(pl); val hhandle = hm.invoke(pl);
val deserialized = am.invoke(null, jsonStr); val deserialized = am.invoke(null, jsonStr);
//val filtered = ffdm.invoke(null, hhandle, deserialized, hhandle); //val filtered = ffdm.invoke(null, hhandle, deserialized, hhandle);
sendmsg.invoke(hhandle, deserialized); Array.set(chatcomparr, 0, deserialized);
if (sendmsg.getParameterCount() == 2)
sendmsg.invoke(hhandle, null, chatcomparr); //
else
sendmsg.invoke(hhandle, chatcomparr);
return true; return true;
} catch (Exception e) { } catch (Exception e) {
e.printStackTrace(); e.printStackTrace();

View file

@ -0,0 +1,15 @@
package buttondevteam.chat.commands;
import buttondevteam.lib.TBMCSystemChatEvent;
import buttondevteam.lib.chat.*;
@CommandClass(helpText = {
"Me",
"Displays a message starting with your name in your current channel."
})
public class MeCommand extends ICommand2MC {
@Command2.Subcommand
public void def(Command2MCSender sender, @Command2.TextArg String message) {
TBMCChatAPI.SendSystemMessage(sender.getChannel(), sender.getChannel().getRTR(sender.getPermCheck()), "§5* " + sender.getSender().getName() + " " + message, TBMCSystemChatEvent.BroadcastTarget.ALL);
}
}

View file

@ -10,7 +10,10 @@ import org.bukkit.command.CommandSender;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Random; import java.util.Random;
@CommandClass(modOnly = true) @CommandClass(modOnly = true, helpText = {
"Snap",
"Perfectly balanced as all things should be."
})
public class SnapCommand extends ICommand2MC { public class SnapCommand extends ICommand2MC {
@Command2.Subcommand @Command2.Subcommand
public void def(CommandSender sender) { public void def(CommandSender sender) {

View file

@ -2,6 +2,7 @@ package buttondevteam.chat.commands.ucmds;
import buttondevteam.lib.chat.Command2; import buttondevteam.lib.chat.Command2;
import buttondevteam.lib.chat.CommandClass; import buttondevteam.lib.chat.CommandClass;
import buttondevteam.lib.chat.CustomTabComplete;
import org.bukkit.command.CommandSender; import org.bukkit.command.CommandSender;
@CommandClass(modOnly = false, helpText = { @CommandClass(modOnly = false, helpText = {
@ -10,7 +11,8 @@ import org.bukkit.command.CommandSender;
}) })
public final class HelpCommand extends UCommandBase { public final class HelpCommand extends UCommandBase {
@Command2.Subcommand @Command2.Subcommand
public boolean def(CommandSender sender, @Command2.TextArg @Command2.OptionalArg String topicOrCommand) { public boolean def(CommandSender sender, @Command2.TextArg @Command2.OptionalArg
@CustomTabComplete({"commands", "chat", "colors"}) String topicOrCommand) {
if (topicOrCommand == null) { if (topicOrCommand == null) {
sender.sendMessage(new String[]{ sender.sendMessage(new String[]{
"§6---- Chroma Help ----", "§6---- Chroma Help ----",
@ -25,33 +27,33 @@ public final class HelpCommand extends UCommandBase {
} }
if (topicOrCommand.equalsIgnoreCase("chat")) if (topicOrCommand.equalsIgnoreCase("chat"))
sender.sendMessage(new String[]{"§6---- Chat features ----", sender.sendMessage(new String[]{"§6---- Chat features ----",
"- [g] Channel identifier: Click it to copy message", "-- [g]: Global chat (/g)", "- [g] Channel identifier: Click it to copy message", "-- [g] Global chat (/g)",
"-- [TC] Town chat (/tc)", "-- [NC] Nation chat (/nc)", "-- [TC] Town chat (/tc)", "-- [NC] Nation chat (/nc)",
"- 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 eligible deaths. This is a reference to CoD:AW's \"Press F to pay respects\""});
else if (topicOrCommand.equalsIgnoreCase("commands")) { else if (topicOrCommand.equalsIgnoreCase("commands")) {
sender.sendMessage(getManager().getCommandsText()); sender.sendMessage(getManager().getCommandsText());
} 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", //
"§0black - &0 | §1dark_blue - &1", // "§0black - &0§r | §1dark_blue - &1§r", //
"§2dark_green - &2 | §3dark_aqua - &3", // "§2dark_green - &2§r | §3dark_aqua - &3§r", //
"§4dark_red - &4 | §5dark_purple - &5", // "§4dark_red - &4§r | §5dark_purple - &5§r", //
"§6gold - &6 | §7gray - &7", // "§6gold - &6§r | §7gray - &7§r", //
"§8dark_gray - &8 | §9blue - &9", // "§8dark_gray - &8§r | §9blue - &9§r", //
"§agreen - &a | §baqua - &b", // "§agreen - &a§r | §baqua - &b§r", //
"§cred - &c | §dlight_purple - &d", // "§cred - &c§r | §dlight_purple - &d§r", //
"§eyellow - &e | §fwhite - &f", // "§eyellow - &e§r | §fwhite - &f§r", //
"§rreset - &r | §kk§robfuscated - &k", // "§rreset - &r | §kk§robfuscated - &k§r", //
"§lbold - &l | §mstrikethrough - &m", // "§lbold - &l§r | §mstrikethrough - &m§r", //
"§nunderline - &n | §oitalic - &o", // "§nunderline - &n§r | §oitalic - &o§r", //
"The format codes in tellraw should be used like \"italic\":\"true\""}); // "The format codes in tellraw should be used like \"italic\":\"true\""}); //
} else { } else {
String[] text = getManager().getHelpText(topicOrCommand); String[] text = getManager().getCommandNode(topicOrCommand).getData().getHelpText(sender); // TODO: This only works for the main command, not subcommands
if (text == null) if (text == null) // TODO: Null check for command node
sender.sendMessage( sender.sendMessage(
new String[]{"§cError: Command not found: " + topicOrCommand, new String[]{"§cError: Command not found: " + topicOrCommand,
"Usage example: /u accept --> /u help u accept"}); "Usage example: /u accept --> /u help u accept"});
else else
sender.sendMessage(text); sender.sendMessage(text);
} }

View file

@ -5,9 +5,9 @@ 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;
import buttondevteam.lib.chat.CommandClass; import buttondevteam.lib.chat.CommandClass;
import lombok.RequiredArgsConstructor; import buttondevteam.lib.chat.CustomTabCompleteMethod;
import buttondevteam.lib.player.ChromaGamerBase;
import lombok.val; import lombok.val;
import org.bukkit.command.CommandSender;
import java.util.*; import java.util.*;
import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.atomic.AtomicBoolean;
@ -15,7 +15,7 @@ import java.util.function.Function;
import java.util.stream.Stream; import java.util.stream.Stream;
@CommandClass(helpText = { @CommandClass(helpText = {
"§6--- Chat History ----", // "Chat History", //
"Returns the last 10 messages the player can see." // "Returns the last 10 messages the player can see." //
}) })
public class HistoryCommand extends UCommandBase { public class HistoryCommand extends UCommandBase {
@ -25,22 +25,22 @@ public class HistoryCommand extends UCommandBase {
private static final 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(ChromaGamerBase sender, @Command2.OptionalArg String channel) {
return showHistory(sender, channel); return showHistory(sender, channel);
} }
public static boolean showHistory(CommandSender sender, String channel) { public static boolean showHistory(ChromaGamerBase sender, String channel) {
if (!PluginMain.Instance.storeChatHistory().get()) { if (!PluginMain.Instance.storeChatHistory.get()) {
sender.sendMessage("§6Chat history is disabled"); sender.sendMessage("§6Chat history is disabled");
return true; 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.getIdentifier() + "_" + 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;
if (channel == null) { if (channel == null) {
stream = Channel.getChannels(); stream = Channel.getChannels();
} else { } else {
Optional<Channel> och = Channel.getChannels().filter(chan -> chan.ID.equalsIgnoreCase(channel)).findAny(); Optional<Channel> och = Channel.getChannels().filter(chan -> chan.getIdentifier().equalsIgnoreCase(channel)).findAny();
if (!och.isPresent()) { if (!och.isPresent()) {
sender.sendMessage("§cChannel not found. Use the ID, for example: /u history g"); sender.sendMessage("§cChannel not found. Use the ID, for example: /u history g");
return true; return true;
@ -54,7 +54,7 @@ public class HistoryCommand extends UCommandBase {
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.getUser().getName() + ": " + cm.getMessage());
sent.set(true); sent.set(true);
} }
} }
@ -63,22 +63,23 @@ public class HistoryCommand extends UCommandBase {
return true; return true;
} }
@RequiredArgsConstructor @CustomTabCompleteMethod(param = "channel")
private static class HistoryEntry { public Iterable<String> def() {
/** return Channel.getChannels().map(Channel::getIdentifier)::iterator;
* System.nanoTime() }
*/
private final long timestamp; /**
private final ChatMessage chatMessage; * @param timestamp System.nanoTime()
private final Channel channel; */
private record HistoryEntry(long timestamp, ChatMessage chatMessage, Channel channel) {
} }
public static void addChatMessage(ChatMessage chatMessage, Channel channel) { public static void addChatMessage(ChatMessage chatMessage, Channel channel) {
if (!PluginMain.Instance.storeChatHistory().get()) return; 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
synchronized (messages) { synchronized (messages) {
var ll = messages.computeIfAbsent(channel.ID + "_" + groupID, k -> new LinkedList<>()); //<-- TIL var ll = messages.computeIfAbsent(channel.getIdentifier() + "_" + groupID, k -> new LinkedList<>()); //<-- TIL
ll.add(new HistoryEntry(System.nanoTime(), chatMessage, channel)); //Adds as last element ll.add(new HistoryEntry(System.nanoTime(), chatMessage, channel)); //Adds as last element
while (ll.size() > 10) while (ll.size() > 10)
ll.remove(); //Removes the first element ll.remove(); //Removes the first element

View file

@ -1,13 +1,13 @@
package buttondevteam.chat.commands.ucmds; package buttondevteam.chat.commands.ucmds;
import buttondevteam.chat.PluginMain; import buttondevteam.chat.PluginMain;
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.Bukkit;
import org.bukkit.OfflinePlayer;
import org.bukkit.command.CommandSender; import org.bukkit.command.CommandSender;
@CommandClass(modOnly = false, helpText = { @CommandClass(modOnly = false, helpText = {
@ -16,23 +16,14 @@ import org.bukkit.command.CommandSender;
}) })
public class InfoCommand extends UCommandBase { public class InfoCommand extends UCommandBase {
@Command2.Subcommand @Command2.Subcommand
public boolean def(CommandSender sender, String player) { public boolean def(CommandSender sender, OfflinePlayer player) {
if (player.equalsIgnoreCase("console") || player.equalsIgnoreCase("server")
|| player.equalsIgnoreCase("@console")) {
sender.sendMessage("The server console.");
return true;
}
Bukkit.getScheduler().runTaskAsynchronously(PluginMain.Instance, () -> { Bukkit.getScheduler().runTaskAsynchronously(PluginMain.Instance, () -> {
try (TBMCPlayer p = TBMCPlayerBase.getFromName(player, TBMCPlayer.class)) { TBMCPlayer p = TBMCPlayerBase.getPlayer(player.getUniqueId(), TBMCPlayer.class);
if (p == null) { if (p == null) {
sender.sendMessage("§cThe specified player cannot be found"); sender.sendMessage("§cThe specified player cannot be found");
return; 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));
}); });
return true; return true;
} }

View file

@ -13,7 +13,7 @@ public class DebugCommand extends AdminCommandBase {
public static boolean DebugMode = false; public static boolean DebugMode = false;
@Command2.Subcommand @Command2.Subcommand
public boolean def(CommandSender sender, String alias, String[] args) { public boolean def(CommandSender sender) {
sender.sendMessage("§eDebug mode " + ((DebugMode = !DebugMode) ? "§aenabled." : "§cdisabled.")); sender.sendMessage("§eDebug mode " + ((DebugMode = !DebugMode) ? "§aenabled." : "§cdisabled."));
return true; return true;
} }

View file

@ -1,10 +1,7 @@
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.FormatterComponent;
import buttondevteam.chat.components.formatter.formatting.TellrawEvent;
import buttondevteam.chat.components.formatter.formatting.TellrawPart;
import buttondevteam.core.ComponentManager; import buttondevteam.core.ComponentManager;
import buttondevteam.lib.chat.Command2; import buttondevteam.lib.chat.Command2;
import buttondevteam.lib.chat.CommandClass; import buttondevteam.lib.chat.CommandClass;
@ -13,6 +10,12 @@ import lombok.val;
import org.bukkit.Bukkit; import org.bukkit.Bukkit;
import org.bukkit.command.CommandSender; import org.bukkit.command.CommandSender;
import static net.kyori.adventure.text.Component.text;
import static net.kyori.adventure.text.event.ClickEvent.Action.SUGGEST_COMMAND;
import static net.kyori.adventure.text.event.ClickEvent.clickEvent;
import static net.kyori.adventure.text.event.HoverEvent.Action.SHOW_TEXT;
import static net.kyori.adventure.text.event.HoverEvent.hoverEvent;
@CommandClass(modOnly = true) @CommandClass(modOnly = true)
@RequiredArgsConstructor @RequiredArgsConstructor
public class AnnounceCommand extends UCommandBase { public class AnnounceCommand extends UCommandBase {
@ -24,7 +27,7 @@ public class AnnounceCommand extends UCommandBase {
}) })
public boolean add(CommandSender sender, @Command2.TextArg String text) { public boolean add(CommandSender sender, @Command2.TextArg String text) {
String finalmessage = text.replace('&', '§'); String finalmessage = text.replace('&', '§');
component.announceMessages().get().add(finalmessage); component.announceMessages.get().add(finalmessage);
sender.sendMessage("§bAnnouncement added.§r"); sender.sendMessage("§bAnnouncement added.§r");
return true; return true;
} }
@ -38,9 +41,9 @@ public class AnnounceCommand extends UCommandBase {
String finalmessage1 = text.replace('&', '§'); String finalmessage1 = text.replace('&', '§');
if (index > 100) if (index > 100)
return false; return false;
while (component.announceMessages().get().size() <= index) while (component.announceMessages.get().size() <= index)
component.announceMessages().get().add(""); component.announceMessages.get().add("");
component.announceMessages().get().set(index, finalmessage1); component.announceMessages.get().set(index, finalmessage1);
sender.sendMessage("Announcement edited."); sender.sendMessage("Announcement edited.");
return true; return true;
} }
@ -53,21 +56,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()) {
String msg = "[" + i++ + "] " + message; String msg = "[" + i++ + "] " + message;
//noinspection SuspiciousMethodCalls //noinspection SuspiciousMethodCalls
if (!ComponentManager.isEnabled(FormatterComponent.class) || !Bukkit.getOnlinePlayers().contains(sender)) { if (!ComponentManager.isEnabled(FormatterComponent.class) || !Bukkit.getOnlinePlayers().contains(sender)) {
sender.sendMessage(msg); sender.sendMessage(msg);
continue; continue;
} }
String json = ChatProcessing.toJson(new TellrawPart(msg) sender.sendMessage(text(msg)
.setHoverEvent(TellrawEvent.create(TellrawEvent.HoverAction.SHOW_TEXT, "Click to edit")) .hoverEvent(hoverEvent(SHOW_TEXT, text("Click to edit")))
.setClickEvent(TellrawEvent.create(TellrawEvent.ClickAction.SUGGEST_COMMAND, .clickEvent(clickEvent(SUGGEST_COMMAND, "/" + getCommandPath() + " edit " + (i - 1) + " " + message.replace('§', '&'))));
"/" + 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;
} }
@ -76,7 +77,7 @@ public class AnnounceCommand extends UCommandBase {
"This command removes an announcement" "This command removes an announcement"
}) })
public boolean remove(CommandSender sender, int index) { public boolean remove(CommandSender sender, int index) {
val msgs = component.announceMessages().get(); val msgs = component.announceMessages.get();
if (index < 0 || index > msgs.size()) return false; if (index < 0 || index > msgs.size()) return false;
msgs.remove(index); msgs.remove(index);
sender.sendMessage("Announcement removed."); sender.sendMessage("Announcement removed.");
@ -88,7 +89,7 @@ public class AnnounceCommand extends UCommandBase {
"This command sets the time between the announcements" "This command sets the time between the announcements"
}) })
public boolean settime(CommandSender sender, int minutes) { public boolean settime(CommandSender sender, int minutes) {
component.announceTime().set(minutes * 60 * 1000); component.announceTime.set(minutes * 60 * 1000);
sender.sendMessage("Time set between announce messages to " + minutes + " minutes"); sender.sendMessage("Time set between announce messages to " + minutes + " minutes");
return true; return true;
} }

View file

@ -4,28 +4,28 @@ import buttondevteam.chat.PluginMain;
import buttondevteam.core.component.channel.Channel; 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.ComponentMetadata;
import buttondevteam.lib.architecture.ListConfigData; import buttondevteam.lib.architecture.config.IConfigData;
import buttondevteam.lib.architecture.config.IListConfigData;
import buttondevteam.lib.chat.TBMCChatAPI; import buttondevteam.lib.chat.TBMCChatAPI;
import org.bukkit.Bukkit; import org.bukkit.Bukkit;
import java.util.Collections;
/** /**
* Displays the configured messages at the set interval when someone is online. * Displays the configured messages at the set interval when someone is online.
*/ */
@ComponentMetadata(enabledByDefault = false)
public class AnnouncerComponent extends Component<PluginMain> implements Runnable { public class AnnouncerComponent extends Component<PluginMain> implements Runnable {
/** /**
* The messages to display to players. * The messages to display to players.
*/ */
public ListConfigData<String> announceMessages() { public IListConfigData<String> announceMessages = getConfig().getListData("announceMessages", Collections.emptyList());
return getConfig().getListData("announceMessages");
}
/** /**
* The time in milliseconds between the messages. Use /u announce settime to set minutes. * The time in milliseconds between the messages. Use /u announce settime to set minutes.
*/ */
public ConfigData<Integer> announceTime() { public IConfigData<Integer> announceTime = getConfig().getData("announceTime", 15 * 60 * 1000);
return getConfig().getData("announceTime", 15 * 60 * 1000);
}
private TBMCSystemChatEvent.BroadcastTarget target; private TBMCSystemChatEvent.BroadcastTarget target;
@ -35,15 +35,15 @@ public class AnnouncerComponent extends Component<PluginMain> implements Runnabl
public void run() { public void run() {
while (isEnabled()) { while (isEnabled()) {
try { try {
Thread.sleep(announceTime().get()); Thread.sleep(announceTime.get());
} catch (InterruptedException ex) { } catch (InterruptedException ex) {
Thread.currentThread().interrupt(); Thread.currentThread().interrupt();
} }
if (Bukkit.getOnlinePlayers().size() == 0) continue; //Don't post to Discord if nobody is on if (Bukkit.getOnlinePlayers().size() == 0) continue; //Don't post to Discord if nobody is on
if (announceMessages().get().size() > AnnounceMessageIndex) { if (announceMessages.get().size() > AnnounceMessageIndex) {
TBMCChatAPI.SendSystemMessage(Channel.GlobalChat, Channel.RecipientTestResult.ALL, announceMessages().get().get(AnnounceMessageIndex), target); TBMCChatAPI.SendSystemMessage(Channel.globalChat, Channel.RecipientTestResult.ALL, announceMessages.get().get(AnnounceMessageIndex), target);
AnnounceMessageIndex++; AnnounceMessageIndex++;
if (AnnounceMessageIndex == announceMessages().get().size()) if (AnnounceMessageIndex == announceMessages.get().size())
AnnounceMessageIndex = 0; AnnounceMessageIndex = 0;
} }
} }

View file

@ -2,12 +2,10 @@ package buttondevteam.chat.components.appendext;
import buttondevteam.chat.PluginMain; import buttondevteam.chat.PluginMain;
import buttondevteam.lib.architecture.Component; import buttondevteam.lib.architecture.Component;
import buttondevteam.lib.architecture.ConfigData;
import buttondevteam.lib.architecture.IHaveConfig; import buttondevteam.lib.architecture.IHaveConfig;
import buttondevteam.lib.architecture.config.IConfigData;
import buttondevteam.lib.chat.*; import buttondevteam.lib.chat.*;
import buttondevteam.lib.player.ChromaGamerBase;
import lombok.val; import lombok.val;
import org.bukkit.command.CommandSender;
import java.lang.reflect.Method; import java.lang.reflect.Method;
import java.util.HashMap; import java.util.HashMap;
@ -21,16 +19,16 @@ import java.util.function.Consumer;
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 IConfigData<String[]> helpText(IHaveConfig config) {
return config.getData("helpText", () -> new String[]{ return config.getData("helpText", new String[]{
"Tableflip", // "Tableflip", //
"This command appends a tableflip after your message", // "This command appends a tableflip after your message", //
"Or just makes you tableflip", // "Or just makes you tableflip", //
}); });
} }
private ConfigData<String> appendedText(IHaveConfig config) { private IConfigData<String> appendedText(IHaveConfig config) {
return config.getData("appendedText", () -> "tableflip"); return config.getData("appendedText", "tableflip");
} }
@Override @Override
@ -68,7 +66,7 @@ public class AppendTextComponent extends Component<PluginMain> {
}); });
appendedText(conf).set("( ͡° ͜ʖ ͡°)"); appendedText(conf).set("( ͡° ͜ʖ ͡°)");
}); });
map.put("ww", conf -> { map.put("waitwhat", conf -> {
helpText(conf).set(new String[]{ helpText(conf).set(new String[]{
"Wait what", // "Wait what", //
"Wait what" // "Wait what" //
@ -101,9 +99,9 @@ public class AppendTextComponent extends Component<PluginMain> {
} }
@Command2.Subcommand @Command2.Subcommand
public void def(CommandSender sender, @Command2.OptionalArg @Command2.TextArg String message) { public void def(Command2MCSender sender, @Command2.OptionalArg @Command2.TextArg String message) {
TBMCChatAPI.SendChatMessage(ChatMessage.builder(sender, ChromaGamerBase.getFromSender(sender), TBMCChatAPI.sendChatMessage(ChatMessage.builder(sender.getSender(),
(message == null ? "" : message + " ") + appendedText).fromCommand(true).build()); (message == null ? "" : message + " ") + appendedText).fromCommand(true).permCheck(sender.getPermCheck()).build());
} }
@Override @Override

View file

@ -2,23 +2,26 @@ package buttondevteam.chat.components.chatonly;
import buttondevteam.chat.ChatPlayer; import buttondevteam.chat.ChatPlayer;
import buttondevteam.chat.PluginMain; import buttondevteam.chat.PluginMain;
import buttondevteam.chat.components.formatter.formatting.TellrawEvent;
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.architecture.ComponentMetadata;
import buttondevteam.lib.player.TBMCPlayer; import buttondevteam.lib.player.TBMCPlayer;
import buttondevteam.lib.player.TBMCPlayerJoinEvent;
import lombok.val; import lombok.val;
import net.kyori.adventure.text.TextComponent;
import org.bukkit.GameMode; import org.bukkit.GameMode;
import org.bukkit.event.EventHandler; import org.bukkit.event.EventHandler;
import org.bukkit.event.EventPriority; import org.bukkit.event.EventPriority;
import org.bukkit.event.Listener; import org.bukkit.event.Listener;
import org.bukkit.event.player.PlayerJoinEvent;
import org.bukkit.event.player.PlayerMoveEvent; import org.bukkit.event.player.PlayerMoveEvent;
import org.bukkit.event.player.PlayerTeleportEvent; import org.bukkit.event.player.PlayerTeleportEvent;
import static net.kyori.adventure.text.Component.text;
import static net.kyori.adventure.text.event.HoverEvent.Action.SHOW_TEXT;
import static net.kyori.adventure.text.event.HoverEvent.hoverEvent;
/** /**
* Allows players to enter chat-only mode which puts them into spectator mode and disallows everything besides chatting. * Allows players to enter chat-only mode which puts them into spectator mode and disallows moving.
*/ */
@ComponentMetadata(enabledByDefault = false) @ComponentMetadata(enabledByDefault = false)
public class ChatOnlyComponent extends Component<PluginMain> implements Listener { public class ChatOnlyComponent extends Component<PluginMain> implements Listener {
@ -34,21 +37,20 @@ public class ChatOnlyComponent extends Component<PluginMain> implements Listener
} }
@EventHandler @EventHandler
public void playerJoin(TBMCPlayerJoinEvent event) { public void playerJoin(PlayerJoinEvent event) {
val p = event.getPlayer(); val p = event.getPlayer();
val cp = event.GetPlayer().asPluginPlayer(ChatPlayer.class); val cp = TBMCPlayer.getPlayer(p.getUniqueId(), ChatPlayer.class);
if (cp.ChatOnly || p.getGameMode().equals(GameMode.SPECTATOR)) { if (cp.ChatOnly || p.getGameMode().equals(GameMode.SPECTATOR)) {
cp.ChatOnly = false; cp.ChatOnly = false;
p.setGameMode(GameMode.SURVIVAL); p.setGameMode(GameMode.SURVIVAL);
} }
} }
public static void tellrawCreate(ChatPlayer mp, TellrawPart json) { public static void tellrawCreate(ChatPlayer mp, TextComponent.Builder json) {
if(!ComponentManager.isEnabled(ChatOnlyComponent.class)) if (!ComponentManager.isEnabled(ChatOnlyComponent.class))
return; return;
if (mp != null && mp.ChatOnly) { if (mp != null && mp.ChatOnly) {
json.addExtra(new TellrawPart("[C]") json.append(text("[C]").hoverEvent(hoverEvent(SHOW_TEXT, text("Chat only"))));
.setHoverEvent(TellrawEvent.create(TellrawEvent.HoverAction.SHOW_TEXT, "Chat only")));
} }
} }

View file

@ -1,6 +1,7 @@
package buttondevteam.chat.components.chatonly; package buttondevteam.chat.components.chatonly;
import buttondevteam.chat.ChatPlayer; import buttondevteam.chat.ChatPlayer;
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.player.TBMCPlayer; import buttondevteam.lib.player.TBMCPlayer;
@ -8,13 +9,14 @@ import org.bukkit.GameMode;
import org.bukkit.entity.Player; import org.bukkit.entity.Player;
@CommandClass(modOnly = false, helpText = { @CommandClass(modOnly = false, helpText = {
"§6---- Chat-only mode ----", // "Chat-only mode", //
"This mode makes you invincible but unable to move, teleport or interact with the world in any way", // "This mode makes you invincible but unable to move, teleport or interact with the world in any way", //
"It was designed for chat clients", // "It was designed for chat clients", //
"Once enabled, the only way of disabling it is by relogging to the server" // "Once enabled, the only way of disabling it is by relogging to the server" //
}) })
public final class ChatonlyCommand extends ICommand2MC { public final class ChatonlyCommand extends ICommand2MC {
@Command2.Subcommand
public boolean def(Player player) { public boolean def(Player player) {
ChatPlayer p = TBMCPlayer.getPlayer(player.getUniqueId(), ChatPlayer.class); ChatPlayer p = TBMCPlayer.getPlayer(player.getUniqueId(), ChatPlayer.class);
p.ChatOnly = true; p.ChatOnly = true;

View file

@ -24,21 +24,21 @@ public class AcceptCommand extends UCommandBase {
@Command2.Subcommand @Command2.Subcommand
public boolean def(Player player, @Command2.OptionalArg String username) { public boolean def(Player player, @Command2.OptionalArg String username) {
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.get().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>");
StringBuilder sb = new StringBuilder(); StringBuilder sb = new StringBuilder();
sb.append("§6Usernames:"); sb.append("§6Usernames:");
for (String name : p.UserNames()) for (String name : p.UserNames.get())
sb.append(" ").append(name); sb.append(" ").append(name);
player.sendMessage(sb.toString()); player.sendMessage(sb.toString());
return true; return true;
} }
if (p.FlairState().get().equals(FlairStates.NoComment) || p.UserNames().size() == 0) { if (p.FlairState.get().equals(FlairStates.NoComment) || p.UserNames.get().size() == 0) {
player.sendMessage("§cError: You need to write your username to the reddit thread§r"); player.sendMessage("§cError: You need to write your username to the reddit thread§r");
player.sendMessage(component.flairThreadURL().get()); player.sendMessage(component.flairThreadURL.get());
return true; return true;
} }
if (username != null && !p.UserNames().contains(username)) { if (username != null && !p.UserNames.get().contains(username)) {
player.sendMessage("§cError: Unknown name: " + username + "§r"); player.sendMessage("§cError: Unknown name: " + username + "§r");
return true; return true;
} }
@ -47,14 +47,14 @@ public class AcceptCommand extends UCommandBase {
return true; return true;
} }
if ((username != null ? username : p.UserNames().get(0)).equals(p.UserName().get())) { if ((username != null ? username : p.UserNames.get().get(0)).equals(p.UserName.get())) {
player.sendMessage("§cYou already have this user's flair.§r"); player.sendMessage("§cYou already have this user's flair.§r");
return true; return true;
} }
if (username != null) if (username != null)
p.UserName().set(username); p.UserName.set(username);
else else
p.UserName().set(p.UserNames().get(0)); p.UserName.set(p.UserNames.get().get(0));
player.sendMessage("§bObtaining flair..."); player.sendMessage("§bObtaining flair...");
p.Working = true; p.Working = true;
@ -65,22 +65,19 @@ public class AcceptCommand extends UCommandBase {
try { try {
component.DownloadFlair(mp); component.DownloadFlair(mp);
} catch (Exception e) { } catch (Exception e) {
TBMCCoreAPI.SendException( TBMCCoreAPI.SendException("An error occured while downloading flair for " + player.getCustomName() + "!", e, component);
"An error occured while downloading flair for " + player.getCustomName() + "!", e); player.sendMessage("Sorry, but an error occured while trying to get your flair. Please contact a mod.");
player.sendMessage(
"Sorry, but an error occured while trying to get your flair. Please contact a mod.");
mp.Working = false; mp.Working = false;
return; return;
} }
if (mp.FlairState().get().equals(FlairStates.Commented)) { if (mp.FlairState.get().equals(FlairStates.Commented)) {
player.sendMessage( player.sendMessage("Sorry, but your flair isn't recorded. Please ask an admin to set it for you. Also, prepare a comment on /r/thebutton, if possible.");
"Sorry, but your flair isn't recorded. Please ask an admin to set it for you. Also, prepare a comment on /r/thebutton, if possible.");
mp.Working = false; mp.Working = false;
return; return;
} }
String flair = mp.GetFormattedFlair(); String flair = mp.GetFormattedFlair();
mp.FlairState().set(FlairStates.Accepted); mp.FlairState.set(FlairStates.Accepted);
FlairComponent.ConfirmUserMessage(mp); FlairComponent.ConfirmUserMessage(mp);
player.sendMessage("§bYour flair has been set:§r " + flair); player.sendMessage("§bYour flair has been set:§r " + flair);
mp.Working = false; mp.Working = false;

View file

@ -5,23 +5,18 @@ 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.ComponentMetadata;
import buttondevteam.lib.architecture.ConfigData; import buttondevteam.lib.architecture.config.IConfigData;
import buttondevteam.lib.player.TBMCPlayerBase; import buttondevteam.lib.player.TBMCPlayerBase;
import com.google.gson.JsonArray; import com.google.gson.JsonArray;
import com.google.gson.JsonObject; import com.google.gson.JsonObject;
import com.google.gson.JsonParser; import com.google.gson.JsonParser;
import org.bukkit.Bukkit; import org.bukkit.Bukkit;
import org.bukkit.entity.Player; import org.bukkit.entity.Player;
import org.htmlcleaner.HtmlCleaner;
import org.htmlcleaner.TagNode;
import java.io.IOException; import java.io.IOException;
import java.io.InputStream;
import java.net.URL;
import java.net.URLConnection;
import java.net.UnknownHostException; import java.net.UnknownHostException;
import java.text.SimpleDateFormat; import java.util.HashSet;
import java.util.*; import java.util.Set;
/** /**
* 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 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.
@ -32,9 +27,7 @@ public class FlairComponent extends Component<PluginMain> {
/** /**
* The Reddit thread to check for account connections. Re-enable the component if this was empty. * The Reddit thread to check for account connections. Re-enable the component if this was empty.
*/ */
ConfigData<String> flairThreadURL() { IConfigData<String> flairThreadURL = getConfig().getData("flairThreadURL", "");
return getConfig().getData("flairThreadURL", "");
}
/** /**
* <p> * <p>
@ -44,7 +37,7 @@ public class FlairComponent extends Component<PluginMain> {
* It's used because normally it has to load all associated player files every time to read the flair state * It's used because normally it has to load all associated player files every time to read the flair state
* </p> * </p>
*/ */
private Set<String> PlayersWithFlairs = new HashSet<>(); private final Set<String> PlayersWithFlairs = new HashSet<>();
@Override @Override
protected void enable() { protected void enable() {
@ -61,9 +54,9 @@ public class FlairComponent extends Component<PluginMain> {
private void FlairGetterThreadMethod() { private void FlairGetterThreadMethod() {
int errorcount = 0; int errorcount = 0;
while (isEnabled() && flairThreadURL().get().length() > 0) { 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")
.getAsJsonObject().get("children").getAsJsonArray(); .getAsJsonObject().get("children").getAsJsonArray();
for (Object obj : json) { for (Object obj : json) {
@ -83,20 +76,19 @@ public class FlairComponent extends Component<PluginMain> {
ign = ign.trim(); ign = ign.trim();
if (PlayersWithFlairs.contains(ign)) if (PlayersWithFlairs.contains(ign))
continue; continue;
try (ChatPlayer mp = TBMCPlayerBase.getFromName(ign, ChatPlayer.class)) { // Loads player file ChatPlayer mp = TBMCPlayerBase.getFromName(ign, ChatPlayer.class); // Loads player file
if (mp == null) if (mp == null)
continue; continue;
/* /*
* if (!JoinedBefore(mp, 2015, 6, 5)) continue; * if (!JoinedBefore(mp, 2015, 6, 5)) continue;
*/ */
if (!mp.UserNames().contains(author)) if (!mp.UserNames.get().contains(author))
mp.UserNames().add(author); mp.UserNames.get().add(author);
if (mp.FlairState().get().equals(FlairStates.NoComment)) { if (mp.FlairState.get().equals(FlairStates.NoComment)) {
mp.FlairState().set(FlairStates.Commented); mp.FlairState.set(FlairStates.Commented);
ConfirmUserMessage(mp); ConfirmUserMessage(mp);
}
PlayersWithFlairs.add(ign); // Don't redownload even if flair isn't accepted
} }
PlayersWithFlairs.add(ign); // Don't redownload even if flair isn't accepted
} }
} catch (Exception e) { } catch (Exception e) {
errorcount++; errorcount++;
@ -104,7 +96,7 @@ public class FlairComponent extends Component<PluginMain> {
errorcount = 0; errorcount = 0;
if (!e.getMessage().contains("Server returned HTTP response code") if (!e.getMessage().contains("Server returned HTTP response code")
&& !(e instanceof UnknownHostException)) && !(e instanceof UnknownHostException))
TBMCCoreAPI.SendException("Error while getting flairs from Reddit!", e); TBMCCoreAPI.SendException("Error while getting flairs from Reddit!", e, this);
} }
} }
try { try {
@ -113,11 +105,12 @@ public class FlairComponent extends Component<PluginMain> {
Thread.currentThread().interrupt(); Thread.currentThread().interrupt();
} }
} }
} }
void DownloadFlair(ChatPlayer mp) throws IOException { void DownloadFlair(ChatPlayer mp) throws IOException {
String[] flairdata = TBMCCoreAPI String[] flairdata = TBMCCoreAPI
.DownloadString("http://karmadecay.com/thebutton-data.php?users=" + mp.UserName().get()) .DownloadString("http://karmadecay.com/thebutton-data.php?users=" + mp.UserName.get())
.replace("\"", "").split(":"); .replace("\"", "").split(":");
String flair; String flair;
if (flairdata.length > 1) if (flairdata.length > 1)
@ -129,12 +122,12 @@ public class FlairComponent extends Component<PluginMain> {
flairclass = flairdata[2]; flairclass = flairdata[2];
else else
flairclass = "unknown"; flairclass = "unknown";
SetFlair(mp, flair, flairclass, mp.UserName().get()); SetFlair(mp, flair, flairclass, mp.UserName.get());
} }
private static void SetFlair(ChatPlayer p, String text, String flairclass, String username) { private void SetFlair(ChatPlayer p, String text, String flairclass, String username) {
p.UserName().set(username); p.UserName.set(username);
p.FlairState().set(FlairStates.Recognised); p.FlairState.set(FlairStates.Recognised);
switch (flairclass) { switch (flairclass) {
case "cheater": case "cheater":
p.SetFlair(Short.parseShort(text), true); p.SetFlair(Short.parseShort(text), true);
@ -150,9 +143,9 @@ public class FlairComponent extends Component<PluginMain> {
p.SetFlair(ChatPlayer.FlairTimeCantPress); p.SetFlair(ChatPlayer.FlairTimeCantPress);
} }
} catch (Exception e) { } catch (Exception e) {
p.FlairState().set(FlairStates.Commented); // Flair unknown p.FlairState.set(FlairStates.Commented); // Flair unknown
p.SetFlair(ChatPlayer.FlairTimeNone); p.SetFlair(ChatPlayer.FlairTimeNone);
TBMCCoreAPI.SendException("Error while checking join date for player " + p.PlayerName() + "!", e); TBMCCoreAPI.SendException("Error while checking join date for player " + p.getPlayerName() + "!", e, this);
} }
return; return;
default: default:
@ -166,7 +159,7 @@ public class FlairComponent extends Component<PluginMain> {
} }
private static boolean JoinedBefore(ChatPlayer mp, int year, int month, int day) throws Exception { private static boolean JoinedBefore(ChatPlayer mp, int year, int month, int day) throws Exception {
URL url = new URL("https://www.reddit.com/u/" + mp.UserName()); /*URL url = new URL("https://www.reddit.com/u/" + mp.UserName());
URLConnection con = url.openConnection(); URLConnection con = url.openConnection();
con.setRequestProperty("User-Agent", "TheButtonAutoFlair"); con.setRequestProperty("User-Agent", "TheButtonAutoFlair");
InputStream in = con.getInputStream(); InputStream in = con.getInputStream();
@ -180,13 +173,14 @@ public class FlairComponent extends Component<PluginMain> {
joindate = joindate.split("T")[0]; joindate = joindate.split("T")[0];
Date date = parserSDF.parse(joindate); Date date = parserSDF.parse(joindate);
return date.before(new Calendar.Builder().setTimeZone(TimeZone.getTimeZone("UTC")).setDate(year, month, day) return date.before(new Calendar.Builder().setTimeZone(TimeZone.getTimeZone("UTC")).setDate(year, month, day)
.build().getTime()); .build().getTime());*/
return true;
} }
public static void ConfirmUserMessage(ChatPlayer mp) { public static void ConfirmUserMessage(ChatPlayer mp) {
Player p = Bukkit.getPlayer(mp.getUUID()); Player p = Bukkit.getPlayer(mp.getUniqueId());
if (mp.FlairState().get().equals(FlairStates.Commented) && p != null) if (mp.FlairState.get().equals(FlairStates.Commented) && p != null)
if (mp.UserNames().size() > 1) if (mp.UserNames.get().size() > 1)
p.sendMessage( p.sendMessage(
"§9Multiple Reddit users commented your name. You can select with /u accept.§r §6Type /u accept or /u ignore§r"); "§9Multiple Reddit users commented your name. You can select with /u accept.§r §6Type /u accept or /u ignore§r");
else else

View file

@ -15,18 +15,18 @@ public final class IgnoreCommand extends UCommandBase {
@Command2.Subcommand @Command2.Subcommand
public boolean def(Player player) { public boolean def(Player player) {
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.");
return true; return true;
} }
if (p.FlairState().get().equals(FlairStates.Commented)) { if (p.FlairState.get().equals(FlairStates.Commented)) {
player.sendMessage("Sorry, but your flair isn't recorded. Please ask a mod to set it for you."); player.sendMessage("Sorry, but your flair isn't recorded. Please ask a mod to set it for you.");
return true; return true;
} }
if (!p.FlairState().get().equals(FlairStates.Ignored)) { if (!p.FlairState.get().equals(FlairStates.Ignored)) {
p.FlairState().set(FlairStates.Ignored); p.FlairState.set(FlairStates.Ignored);
p.SetFlair(ChatPlayer.FlairTimeNone); p.SetFlair(ChatPlayer.FlairTimeNone);
p.UserName().set(""); p.UserName.set("");
player.sendMessage("§bYou have ignored the message.§r"); player.sendMessage("§bYou have ignored the message.§r");
} else } else
player.sendMessage("§cYou already ignored the message.§r"); player.sendMessage("§cYou already ignored the message.§r");

View file

@ -10,7 +10,7 @@ import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player; import org.bukkit.entity.Player;
@CommandClass(helpText = { @CommandClass(helpText = {
"§6---- Set flair -----", "Set a flair for a player", "Set flair", "Set a flair for a player",
"Usage: /u admin setflair <player> <flairtime (or non-presser, cant-press, none)> <cheater(true/false)> [username]", "Usage: /u admin setflair <player> <flairtime (or non-presser, cant-press, none)> <cheater(true/false)> [username]",
"Example 1: /u admin setflair NorbiPeti 19 false NorbiPeti --> orange (19s)", "Example 1: /u admin setflair NorbiPeti 19 false NorbiPeti --> orange (19s)",
"Example 2: /u admin setflair iie 0 true asde --> purple (0s)" "Example 2: /u admin setflair iie 0 true asde --> purple (0s)"
@ -35,22 +35,21 @@ public class SetFlairCommand extends AdminCommandBase {
ft = Short.parseShort(flairtime); ft = Short.parseShort(flairtime);
} catch (Exception e) { } catch (Exception e) {
sender.sendMessage( sender.sendMessage(
"§cFlairtime must be a number, \"non-presser\", \"cant-press\" or \"none\". Run without args to see usage."); "§cFlairtime must be a number, \"non-presser\", \"cant-press\" or \"none\". Run without args to see usage.");
return true; return true;
} }
} }
ChatPlayer mp = TBMCPlayerBase.getPlayer(p.getUniqueId(), ChatPlayer.class); ChatPlayer mp = TBMCPlayerBase.getPlayer(p.getUniqueId(), ChatPlayer.class);
mp.SetFlair(ft, cheater); mp.SetFlair(ft, cheater);
mp.FlairState().set(FlairStates.Accepted); mp.FlairState.set(FlairStates.Accepted);
if (username == null) if (username == null)
mp.UserName().set(""); mp.UserName.set("");
else { else {
mp.UserName().set(username); mp.UserName.set(username);
if (!mp.UserNames().contains(username)) if (!mp.UserNames.get().contains(username))
mp.UserNames().add(username); mp.UserNames.get().add(username);
} }
sender.sendMessage( sender.sendMessage("§bThe flair has been set. Player: " + mp.getPlayerName() + " Flair: " + mp.GetFormattedFlair() + "§r");
"§bThe flair has been set. Player: " + mp.PlayerName() + " Flair: " + mp.GetFormattedFlair() + "§r");
return true; return true;
} }

View file

@ -12,20 +12,22 @@ import buttondevteam.chat.components.towny.TownyComponent;
import buttondevteam.chat.listener.PlayerListener; import buttondevteam.chat.listener.PlayerListener;
import buttondevteam.core.ComponentManager; import buttondevteam.core.ComponentManager;
import buttondevteam.core.component.channel.Channel; import buttondevteam.core.component.channel.Channel;
import buttondevteam.lib.ChromaUtils;
import buttondevteam.lib.TBMCChatEvent; import buttondevteam.lib.TBMCChatEvent;
import buttondevteam.lib.TBMCChatEventBase; import buttondevteam.lib.TBMCChatEventBase;
import buttondevteam.lib.TBMCCoreAPI; import buttondevteam.lib.TBMCCoreAPI;
import buttondevteam.lib.chat.Color;
import buttondevteam.lib.chat.TellrawSerializableEnum;
import buttondevteam.lib.player.ChromaGamerBase; 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.ImmutableList;
import com.google.common.collect.Lists; import com.google.common.collect.Lists;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import lombok.val; import lombok.val;
import net.ess3.api.events.AfkStatusChangeEvent;
import net.kyori.adventure.text.TextComponent;
import net.kyori.adventure.text.format.NamedTextColor;
import net.kyori.adventure.text.format.TextColor;
import net.kyori.adventure.text.format.TextDecoration;
import org.bukkit.Bukkit; import org.bukkit.Bukkit;
import org.bukkit.Sound; import org.bukkit.Sound;
import org.bukkit.command.CommandSender; import org.bukkit.command.CommandSender;
@ -38,16 +40,23 @@ import java.util.function.Consumer;
import java.util.function.Predicate; import java.util.function.Predicate;
import java.util.regex.Pattern; import java.util.regex.Pattern;
import static net.kyori.adventure.text.Component.text;
import static net.kyori.adventure.text.event.ClickEvent.suggestCommand;
import static net.kyori.adventure.text.event.HoverEvent.Action.SHOW_TEXT;
import static net.kyori.adventure.text.event.HoverEvent.hoverEvent;
import static net.kyori.adventure.text.format.NamedTextColor.*;
public class ChatProcessing { 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]+)?)");
private static final Pattern MASKED_LINK_PATTERN = Pattern.compile("\\[([^\\[\\]]+)]\\(([^()]+)\\)"); private static final Pattern MASKED_LINK_PATTERN = Pattern.compile("\\[([^\\[\\]]+)]\\(([^()]+)\\)");
private static final Color[] RainbowPresserColors = new Color[]{Color.Red, Color.Gold, Color.Yellow, Color.Green, private static final NamedTextColor[] RainbowPresserColors = new NamedTextColor[]{RED, GOLD, YELLOW, GREEN,
Color.Blue, Color.DarkPurple}; BLUE, DARK_PURPLE};
private static final Pattern WORD_PATTERN = Pattern.compile("\\S+"); private static final Pattern WORD_PATTERN = Pattern.compile("\\S+");
private static final Pattern GREENTEXT_PATTERN = Pattern.compile("^>(?:.|\\s)*");
private static boolean pingedconsole = false; private static boolean pingedconsole = false;
private static ArrayList<MatchProviderBase> commonFormatters = Lists.newArrayList( private static final ArrayList<MatchProviderBase> commonFormatters = Lists.newArrayList(
new RangeMatchProvider("bold", "**", FormatSettings.builder().bold(true).build()), new RangeMatchProvider("bold", "**", FormatSettings.builder().bold(true).build()),
new RangeMatchProvider("italic", "*", FormatSettings.builder().italic(true).build()), new RangeMatchProvider("italic", "*", FormatSettings.builder().italic(true).build()),
new RangeMatchProvider("underlined", "__", FormatSettings.builder().underlined(true).build()), new RangeMatchProvider("underlined", "__", FormatSettings.builder().underlined(true).build()),
@ -58,8 +67,8 @@ public class ChatProcessing {
cf.setHoverText(match); cf.setHoverText(match);
return match; return match;
}).build()), }).build()),
new StringMatchProvider("nullMention", FormatSettings.builder().color(Color.DarkRed).build(), true, "null"), // Properly added a bug as a feature new StringMatchProvider("nullMention", FormatSettings.builder().color(DARK_RED).build(), true, "null"), // Properly added a bug as a feature
new StringMatchProvider("consolePing", FormatSettings.builder().color(Color.Aqua) new StringMatchProvider("consolePing", FormatSettings.builder().color(AQUA)
.onmatch((match, builder, section) -> { .onmatch((match, builder, section) -> {
if (!pingedconsole) { if (!pingedconsole) {
System.out.print("\007"); System.out.print("\007");
@ -68,19 +77,19 @@ public class ChatProcessing {
return "@console"; return "@console";
}).build(), true, "@console"), }).build(), true, "@console"),
new StringMatchProvider("cyan", FormatSettings.builder().color(Color.Aqua).build(), true, "cyan"), // #55 new StringMatchProvider("cyan", FormatSettings.builder().color(AQUA).build(), true, "cyan"), // #55
new RangeMatchProvider("code", "`", FormatSettings.builder().color(Color.DarkGray).build()), new RangeMatchProvider("code", "`", FormatSettings.builder().color(DARK_GRAY).build()),
new RegexMatchProvider("maskedLink", MASKED_LINK_PATTERN, FormatSettings.builder().underlined(true) new RegexMatchProvider("maskedLink", MASKED_LINK_PATTERN, FormatSettings.builder().underlined(true)
.onmatch((match, builder, section) -> { .onmatch((match, builder, section) -> {
String text, link; String text, link;
if (section.Matches.size() < 2 || (text = section.Matches.get(0)).length() == 0 || (link = section.Matches.get(1)).length() == 0) if (section.Matches.size() < 2 || (text = section.Matches.get(0)).length() == 0 || (link = section.Matches.get(1)).length() == 0)
return ""; return "[MISSING LINK]"; //Doesn't actually happen, because of the regex
builder.setOpenlink(link); builder.setOpenlink(link);
return text; return text;
}).build()), }).build()),
new RegexMatchProvider("url", URL_PATTERN, FormatSettings.builder().underlined(true).openlink("$1").build()), new RegexMatchProvider("url", URL_PATTERN, FormatSettings.builder().underlined(true).openlink("$1").build()),
new RegexMatchProvider("hashtag", HASHTAG_PATTERN, FormatSettings.builder().color(Color.Blue).openlink("https://twitter.com/hashtag/$1").build()), new RegexMatchProvider("hashtag", HASHTAG_PATTERN, FormatSettings.builder().color(BLUE).openlink("https://twitter.com/hashtag/$1").build()),
new StringMatchProvider("someone", FormatSettings.builder().color(Color.Aqua) new StringMatchProvider("someone", FormatSettings.builder().color(AQUA)
.onmatch((match, builder, section) -> { .onmatch((match, builder, section) -> {
if (Bukkit.getOnlinePlayers().size() == 0) return match; if (Bukkit.getOnlinePlayers().size() == 0) return match;
var players = ImmutableList.copyOf(Bukkit.getOnlinePlayers()); var players = ImmutableList.copyOf(Bukkit.getOnlinePlayers());
@ -88,12 +97,8 @@ public class ChatProcessing {
var player = players.get(playerC); var player = players.get(playerC);
playPingSound(player, ComponentManager.getIfEnabled(FormatterComponent.class)); playPingSound(player, ComponentManager.getIfEnabled(FormatterComponent.class));
return "@someone (" + player.getDisplayName() + "§r)"; return "@someone (" + player.getDisplayName() + "§r)";
}).build(), true, "@someone")); }).build(), true, "@someone"),
private static Gson gson = new GsonBuilder() new RegexMatchProvider("greentext", GREENTEXT_PATTERN, FormatSettings.builder().color(GREEN).build()));
.registerTypeHierarchyAdapter(TellrawSerializableEnum.class, new TellrawSerializer.TwEnum())
.registerTypeHierarchyAdapter(Collection.class, new TellrawSerializer.TwCollection())
.registerTypeAdapter(Boolean.class, new TellrawSerializer.TwBool())
.registerTypeAdapter(boolean.class, new TellrawSerializer.TwBool()).disableHtmlEscaping().create();
private static final String[] testPlayers = {"Koiiev", "iie", "Alisolarflare", "NorbiPeti", "Arsen_Derby_FTW", "carrot_lynx"}; private static final String[] testPlayers = {"Koiiev", "iie", "Alisolarflare", "NorbiPeti", "Arsen_Derby_FTW", "carrot_lynx"};
private ChatProcessing() { private ChatProcessing() {
@ -101,70 +106,80 @@ public class ChatProcessing {
public static boolean ProcessChat(TBMCChatEvent e, FormatterComponent component) { public static boolean ProcessChat(TBMCChatEvent e, FormatterComponent component) {
Channel channel = e.getChannel(); Channel channel = e.getChannel();
CommandSender sender = e.getSender(); ChromaGamerBase cuser = e.getUser();
String message = e.getMessage(); String message = e.getMessage();
long processstart = System.nanoTime(); long processstart = System.nanoTime();
Player player = (sender instanceof Player ? (Player) sender : null); Player player = (cuser instanceof TBMCPlayerBase ? ((TBMCPlayerBase) cuser).getPlayer() : null);
User user = PluginMain.essentials.getUser(player); User user = PluginMain.essentials.getUser(player);
if (player != null) { if (player != null && PluginMain.essentials.getSettings().cancelAfkOnInteract()) {
user.updateActivity(true); //Could talk in a private channel, so broadcast user.updateActivity(true, AfkStatusChangeEvent.Cause.CHAT); //Could talk in a private channel, so broadcast
if (user.isMuted()) if (user.isMuted())
return true; return true;
} }
doFunStuff(sender, e, message);
final String channelidentifier = getChannelID(channel, e.getOrigin());
PluginMain.Instance.getServer().getConsoleSender()
.sendMessage(String.format("%s <%s§r> %s", channelidentifier, getSenderName(sender, player), message));
if (Bukkit.getOnlinePlayers().size() == 0) return false; //Don't try to send to nobody (errors on 1.14)
ChatPlayer mp; ChatPlayer mp;
if (player != null) if (player != null)
mp = TBMCPlayerBase.getPlayer(player.getUniqueId(), ChatPlayer.class); mp = TBMCPlayerBase.getPlayer(player.getUniqueId(), ChatPlayer.class);
else //Due to the online player map, getPlayer() can be more efficient than getAs() else //Due to the online player map, getPlayer() can be more efficient than getAs()
mp = e.getUser().getAs(ChatPlayer.class); //May be null mp = e.getUser().getAs(ChatPlayer.class); //May be null
Color colormode = channel.Color().get(); if (mp != null) {
if (mp != null && mp.OtherColorMode != null) if (System.nanoTime() - mp.LastMessageTime < 1000L * 1000L * component.minTimeBetweenMessages.get()) { //0.1s by default
colormode = mp.OtherColorMode; cuser.sendMessage("§cYou are sending messages too quickly!");
if (message.startsWith(">")) return true;
colormode = Color.Green; }
// If greentext, ignore channel or player colors mp.LastMessageTime = System.nanoTime();
}
//DimensionManager.a()
//IRegistry.ae
//Bukkit.createWorld()
//MinecraftServer.reload()
//IRegistry
//CraftServer
doFunStuff(cuser, e, message);
final String channelidentifier = getChannelID(channel, e.getOrigin());
PluginMain.Instance.getServer().getConsoleSender()
.sendMessage(String.format("%s <%s§r> %s", channelidentifier, cuser.getName(), message));
if (Bukkit.getOnlinePlayers().size() == 0) return false; //Don't try to send to nobody (errors on 1.14)
TextColor colormode = NAMES.value(channel.color.get().getName());
boolean colorModeChanged = false;
if (mp != null && mp.OtherColorMode != null) {
colormode = NAMES.value(mp.OtherColorMode.getName());
colorModeChanged = true;
}
ArrayList<MatchProviderBase> formatters; ArrayList<MatchProviderBase> formatters;
if (component.allowFormatting().get()) { if (component.allowFormatting.get()) {
formatters = addFormatters(e::shouldSendTo, component); formatters = addFormatters(sender -> e.shouldSendTo(ChromaGamerBase.getFromSender(sender)), component);
if (colormode == channel.Color().get() && mp != null && mp.RainbowPresserColorMode) { // Only overwrite channel color if (colorModeChanged && mp.RainbowPresserColorMode) { // Only overwrite channel color
createRPC(colormode, formatters); createRPC(colormode, formatters);
} }
pingedconsole = false; // Will set it to true onmatch (static constructor) pingedconsole = false; // Will set it to true onmatch (static constructor)
} else } else
formatters = Lists.newArrayList(); formatters = Lists.newArrayList();
TellrawPart json = createTellraw(sender, message, player, mp, e.getUser(), channelidentifier, e.getOrigin()); TextComponent.Builder builder = createEmptyMessageLine(cuser, message, player, channelidentifier, e.getOrigin());
long combinetime = System.nanoTime(); long combinetime = System.nanoTime();
ChatFormatter.Combine(formatters, message, json, component.getConfig(), FormatSettings.builder().color(colormode).build()); ChatFormatter.Combine(formatters, message, builder, component.getConfig(), FormatSettings.builder().color(colormode).build());
combinetime = System.nanoTime() - combinetime; combinetime = System.nanoTime() - combinetime;
String jsonstr = toJson(json);
if (jsonstr.length() >= 32767) {
sender.sendMessage(
"§cError: Message too long. Try shortening it, or remove hashtags and other formatting.");
return true;
}
DebugCommand.SendDebugMessage(jsonstr);
try { try {
if (!channel.isGlobal()) { if (!channel.isGlobal()) {
String senderGroup = e.getGroupID(sender); String senderGroup = e.getGroupID(cuser);
if (senderGroup == null) { // Never send messages if the group is null if (senderGroup == null) { // Never send messages if the group is null
sender.sendMessage("§cYou don't have permission to send this message or something went wrong"); cuser.sendMessage("§cYou don't have permission to send this message or something went wrong");
return true; return true;
} }
val tc = ComponentManager.getIfEnabled(TownyComponent.class); val tc = ComponentManager.getIfEnabled(TownyComponent.class);
if (tc != null) tc.handleSpiesInit(channel, json, ChatProcessing::toJson); Consumer<Player> spyConsumer = null;
if (tc != null)
spyConsumer = tc.handleSpiesInit(channel, builder);
for (Player p : Bukkit.getOnlinePlayers()) { for (Player p : Bukkit.getOnlinePlayers()) {
final String group; final String group;
if (player != null if (player != null
@ -172,17 +187,18 @@ public class ChatProcessing {
group = null; // Don't send the message to them group = null; // Don't send the message to them
else else
group = VanillaUtils.getGroupIfChatOn(p, e); group = VanillaUtils.getGroupIfChatOn(p, e);
if (senderGroup.equals(group)) if (senderGroup.equals(group)) {
VanillaUtils.tellRaw(p, jsonstr); p.sendMessage(builder.build());
else if (tc != null) tc.handleSpies(channel, p); if (tc != null) spyConsumer.accept(p);
}
//Only sends if didn't send normally //Only sends if didn't send normally
} }
} else } else
for (Player p : Bukkit.getOnlinePlayers()) for (Player p : Bukkit.getOnlinePlayers())
VanillaUtils.tellRaw(p, jsonstr); p.sendMessage(builder.build());
} catch (Exception ex) { } catch (Exception ex) {
TBMCCoreAPI.SendException("An error occured while sending a chat message!", ex); TBMCCoreAPI.SendException("An error occured while sending a chat message!", ex, PluginMain.Instance);
sender.sendMessage("§cAn error occured while sending the message."); cuser.sendMessage("§cAn error occured while sending the message.");
return true; return true;
} }
DebugCommand.SendDebugMessage( DebugCommand.SendDebugMessage(
@ -191,7 +207,7 @@ public class ChatProcessing {
return false; return false;
} }
static void createRPC(Color colormode, ArrayList<MatchProviderBase> formatters) { static void createRPC(TextColor colormode, ArrayList<MatchProviderBase> formatters) {
final AtomicInteger rpc = new AtomicInteger(0); final AtomicInteger rpc = new AtomicInteger(0);
formatters.add(new RegexMatchProvider("rpc", WORD_PATTERN, FormatSettings.builder().color(colormode).onmatch((match, cf, s) -> { formatters.add(new RegexMatchProvider("rpc", WORD_PATTERN, FormatSettings.builder().color(colormode).onmatch((match, cf, s) -> {
cf.setColor(RainbowPresserColors[rpc.getAndUpdate(i -> ++i < RainbowPresserColors.length ? i : 0)]); cf.setColor(RainbowPresserColors[rpc.getAndUpdate(i -> ++i < RainbowPresserColors.length ? i : 0)]);
@ -199,46 +215,29 @@ public class ChatProcessing {
}).build())); }).build()));
} }
public static String toJson(TellrawPart json) { static TextComponent.Builder createEmptyMessageLine(ChromaGamerBase user, String message, @Nullable Player player,
return gson.toJson(json); final String channelidentifier, String origin) {
} val json = text();
ChatOnlyComponent.tellrawCreate(user.getAs(ChatPlayer.class), json);
static TellrawPart createTellraw(CommandSender sender, String message, @Nullable Player player, val channelHover = (ChatUtils.MCORIGIN.equals(origin) ? "" : "From " + origin + "\n") + "Copy message";
@Nullable ChatPlayer mp, @Nullable ChromaGamerBase cg, final String channelidentifier, json.append(text(channelidentifier)
String origin) { .hoverEvent(hoverEvent(SHOW_TEXT, text(channelHover).color(BLUE))).clickEvent(suggestCommand(message)));
TellrawPart json = new TellrawPart(""); if (player != null) {
ChatOnlyComponent.tellrawCreate(mp, json); //TODO: Make nice API if (PluginMain.permission.has(player, "tbmc.badge.diamond")) // TODO: Cross-platform permissions
json.addExtra( json.append(text("[P]").color(AQUA).decorate(TextDecoration.BOLD)
new TellrawPart(channelidentifier) .hoverEvent(hoverEvent(SHOW_TEXT, text("Diamond Patreon supporter"))));
.setHoverEvent( else if (PluginMain.permission.has(player, "tbmc.badge.gold"))
TellrawEvent.create(TellrawEvent.HoverAction.SHOW_TEXT, json.append(text("[P]").color(GOLD).decorate(TextDecoration.BOLD)
new TellrawPart((ChatUtils.MCORIGIN.equals(origin) ? "" : "From " + origin + "n") .hoverEvent(hoverEvent(SHOW_TEXT, text("Gold Patreon supporter"))));
+ "Copy message").setColor(Color.Blue))) }
.setClickEvent(TellrawEvent.create(TellrawEvent.ClickAction.SUGGEST_COMMAND, message))); json.append(text(" <"));
if (PluginMain.permission.has(sender, "tbmc.badge.diamond")) json.append(text(user.getName()).hoverEvent(hoverEvent(SHOW_TEXT, text(user.getInfo(ChromaGamerBase.InfoTarget.MCHover)))));
json.addExtra(new TellrawPart("[P]").setColor(Color.Aqua).setBold(true) json.append(text("> "));
.setHoverEvent(TellrawEvent.create(TellrawEvent.HoverAction.SHOW_TEXT, "Diamond Patreon supporter")));
else if (PluginMain.permission.has(sender, "tbmc.badge.gold"))
json.addExtra(new TellrawPart("[P]").setColor(Color.Gold).setBold(true)
.setHoverEvent(TellrawEvent.create(TellrawEvent.HoverAction.SHOW_TEXT, "Gold Patreon supporter")));
json.addExtra(new TellrawPart(" <"));
TellrawPart hovertp = new TellrawPart("");
if (cg != null)
hovertp.addExtra(new TellrawPart(cg.getInfo(ChromaGamerBase.InfoTarget.MCHover)));
json.addExtra(new TellrawPart(getSenderName(sender, player))
.setHoverEvent(TellrawEvent.create(TellrawEvent.HoverAction.SHOW_TEXT, hovertp)));
json.addExtra(new TellrawPart("> "));
return json; return json;
} }
private static String getSenderName(CommandSender sender, Player player) {
if (player == null)
return sender.getName();
return player.getDisplayName();
}
static String getChannelID(Channel channel, String origin) { static String getChannelID(Channel channel, String origin) {
return ("[" + (ChatUtils.MCORIGIN.equals(origin) ? "" : "§8" + origin.substring(0, 1) + "§r|") + channel.DisplayName().get()) return ("[" + (ChatUtils.MCORIGIN.equals(origin) ? "" : "§8" + origin.charAt(0) + "§r|") + channel.displayName.get())
+ "]"; + "]";
} }
@ -247,7 +246,7 @@ public class ChatProcessing {
ArrayList<MatchProviderBase> formatters = (ArrayList<MatchProviderBase>) commonFormatters.clone(); ArrayList<MatchProviderBase> formatters = (ArrayList<MatchProviderBase>) commonFormatters.clone();
boolean nottest; //Not assigning a default value, so that it can only be used in the if boolean nottest; //Not assigning a default value, so that it can only be used in the if
if ((nottest = Bukkit.getOnlinePlayers().size() > 0) || Bukkit.getVersion().equals("test")) { if ((nottest = Bukkit.getOnlinePlayers().size() > 0) || ChromaUtils.isTest()) {
String[] names; String[] names;
if (nottest) if (nottest)
names = Bukkit.getOnlinePlayers().stream().filter(canSee).map(CommandSender::getName).toArray(String[]::new); names = Bukkit.getOnlinePlayers().stream().filter(canSee).map(CommandSender::getName).toArray(String[]::new);
@ -266,12 +265,12 @@ public class ChatProcessing {
}; };
if (names.length > 0) //Add as first so it handles special characters (_) - though the order of the different types are defined if (names.length > 0) //Add as first so it handles special characters (_) - though the order of the different types are defined
formatters.add(0, new StringMatchProvider("name", FormatSettings.builder().color(Color.Aqua) formatters.add(0, new StringMatchProvider("name", FormatSettings.builder().color(AQUA)
.onmatch((match, builder, section) -> { .onmatch((match, builder, section) -> {
Player p = Bukkit.getPlayer(match); Player p = Bukkit.getPlayer(match);
Optional<String> pn = nottest ? Optional.empty() Optional<String> pn = nottest ? Optional.empty()
: Arrays.stream(testPlayers).filter(tp -> tp.equalsIgnoreCase(match)).findAny(); : Arrays.stream(testPlayers).filter(tp -> tp.equalsIgnoreCase(match)).findAny();
if (nottest ? p == null : !pn.isPresent()) { if (nottest ? p == null : pn.isEmpty()) {
error.accept("Error: Can't find player " + match + " but was reported as online."); error.accept("Error: Can't find player " + match + " but was reported as online.");
return "§c" + match + "§r"; return "§c" + match + "§r";
} }
@ -284,7 +283,7 @@ public class ChatProcessing {
}).build(), true, names)); }).build(), true, names));
if (nicknames.length > 0) //Add as first so it handles special characters if (nicknames.length > 0) //Add as first so it handles special characters
formatters.add(0, new StringMatchProvider("nickname", FormatSettings.builder().color(Color.Aqua) formatters.add(0, new StringMatchProvider("nickname", FormatSettings.builder().color(AQUA)
.onmatch((match, builder, section) -> { .onmatch((match, builder, section) -> {
if (PlayerListener.nicknames.containsKey(match.toLowerCase())) { //Made a stream and all that but I can actually store it lowercased if (PlayerListener.nicknames.containsKey(match.toLowerCase())) { //Made a stream and all that but I can actually store it lowercased
Player p = Bukkit.getPlayer(PlayerListener.nicknames.get(match.toLowerCase())); Player p = Bukkit.getPlayer(PlayerListener.nicknames.get(match.toLowerCase()));
@ -305,15 +304,15 @@ public class ChatProcessing {
} }
private static void playPingSound(Player p, @Nullable FormatterComponent component) { private static void playPingSound(Player p, @Nullable FormatterComponent component) {
if (component == null || component.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(), component.notificationSound().get(), 1.0f, p.playSound(p.getLocation(), component.notificationSound.get(), 1.0f,
component.notificationPitch().get()); component.notificationPitch.get());
} }
static void doFunStuff(CommandSender sender, TBMCChatEventBase event, String message) { static void doFunStuff(ChromaGamerBase user, TBMCChatEventBase event, String message) {
val fc = ComponentManager.getIfEnabled(FunComponent.class); val fc = ComponentManager.getIfEnabled(FunComponent.class);
if (fc != null) fc.onChat(sender, event, message); if (fc != null) fc.onChat(user, event, message);
} }
} }

View file

@ -5,44 +5,42 @@ import buttondevteam.core.ComponentManager;
import buttondevteam.core.MainPlugin; import buttondevteam.core.MainPlugin;
import buttondevteam.lib.TBMCChatEvent; import buttondevteam.lib.TBMCChatEvent;
import buttondevteam.lib.architecture.Component; import buttondevteam.lib.architecture.Component;
import buttondevteam.lib.architecture.ConfigData; import buttondevteam.lib.architecture.config.IConfigData;
/** /**
* This component handles the custom processing of chat messages. If this component is disabled channels won't be supported 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. * If you're using another chat plugin, you should disable the whole component but that will make it impossible to use channels.
*/ */
public class FormatterComponent extends Component<PluginMain> { public class FormatterComponent extends Component<PluginMain> {
/** /**
* Determines whether Markdown formatting, name mentioning and similar features are enabled. * Determines whether Markdown formatting, name mentioning and similar features are enabled.
*/ */
ConfigData<Boolean> allowFormatting() { IConfigData<Boolean> allowFormatting = getConfig().getData("allowFormatting", true);
return getConfig().getData("allowFormatting", true);
}
/** /**
* The sound to play when a player is mentioned. Leave empty to use default. * The sound to play when a player is mentioned. Leave empty to use default.
*/ */
public ConfigData<String> notificationSound() { public IConfigData<String> notificationSound = getConfig().getData("notificationSound", "");
return getConfig().getData("notificationSound", "");
}
/** /**
* The pitch of the notification sound. * The pitch of the notification sound.
*/ */
public ConfigData<Float> notificationPitch() { public IConfigData<Float> notificationPitch = getConfig().getData("notificationPitch", 1.0f);
return getConfig().getData("notificationPitch", 1.0f);
}
/**
* The minimum time between messages in milliseconds.
*/
public IConfigData<Integer> minTimeBetweenMessages = getConfig().getData("minTimeBetweenMessages", 100);
@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.getInstance().setChatHandlerEnabled(false); //Disable Core chat handler - if this component is disabled then let it do its job
} }
@Override @Override
protected void disable() { protected void disable() {
MainPlugin.Instance.setChatHandlerEnabled(true); MainPlugin.getInstance().setChatHandlerEnabled(true);
} }
/** /**

View file

@ -2,15 +2,24 @@ package buttondevteam.chat.components.formatter.formatting;
import buttondevteam.chat.commands.ucmds.admin.DebugCommand; import buttondevteam.chat.commands.ucmds.admin.DebugCommand;
import buttondevteam.lib.architecture.IHaveConfig; import buttondevteam.lib.architecture.IHaveConfig;
import buttondevteam.lib.chat.Color;
import lombok.val; import lombok.val;
import net.kyori.adventure.text.TextComponent;
import net.kyori.adventure.text.format.NamedTextColor;
import net.kyori.adventure.text.format.TextDecoration;
import org.jetbrains.annotations.NotNull;
import java.util.*; import java.util.*;
import java.util.function.Predicate; import java.util.function.Predicate;
import java.util.stream.Collectors; import java.util.stream.Collectors;
import static net.kyori.adventure.text.Component.text;
import static net.kyori.adventure.text.event.ClickEvent.Action.OPEN_URL;
import static net.kyori.adventure.text.event.ClickEvent.clickEvent;
import static net.kyori.adventure.text.event.HoverEvent.Action.SHOW_TEXT;
import static net.kyori.adventure.text.event.HoverEvent.hoverEvent;
/** /**
* A {@link MatchProvider} finds where the given {@link FormatSettings} need to be applied. {@link ChatFormatter#Combine(List, String, TellrawPart, IHaveConfig, FormatSettings)}} is used to turn it into a {@link TellrawPart}, combining * A {@link MatchProvider} finds where the given {@link FormatSettings} need to be applied. {@link ChatFormatter#Combine(List, String, TextComponent.Builder, IHaveConfig, FormatSettings)}} is used to turn it into a {@link TellrawPart}, combining
* intersecting parts found, for example when {@code _abc*def*ghi_} is said in chat, it'll turn it into an underlined part, then an underlined <i>and italics</i> part, finally an underlined part * intersecting parts found, for example when {@code _abc*def*ghi_} is said in chat, it'll turn it into an underlined part, then an underlined <i>and italics</i> part, finally an underlined part
* again. * again.
* *
@ -26,7 +35,7 @@ public final class ChatFormatter {
} }
//synchronized: Some of the formatters are reused, see createSections(...) //synchronized: Some of the formatters are reused, see createSections(...)
public static synchronized void Combine(List<MatchProviderBase> formatters, String str, TellrawPart tp, IHaveConfig config, FormatSettings defaults) { public static synchronized void Combine(List<MatchProviderBase> formatters, String str, TextComponent.Builder tp, IHaveConfig config, FormatSettings defaults) {
/* /*
* A global formatter is no longer needed * A global formatter is no longer needed
*/ */
@ -120,22 +129,25 @@ public final class ChatFormatter {
sortSections(sections); sortSections(sections);
continue; continue;
} else if (firstSection.End >= lastSection.Start && firstSection.Start <= lastSection.End) { } else if (firstSection.End >= lastSection.Start && firstSection.Start <= lastSection.End) {
int firstSectEnd = firstSection.End; int middleStart = lastSection.Start;
firstSection.End = lastSection.Start - 1; // |----|-- |------|
int lastSectEnd = lastSection.End; // --|----| -|----|-
FormattedSection section = new FormattedSection(firstSection.Settings, lastSection.Start, lastSectEnd, int middleEnd = Math.min(lastSection.End, firstSection.End);
int lastSectEnd = Math.max(lastSection.End, firstSection.End);
FormattedSection section = new FormattedSection(firstSection.Settings, middleStart, middleEnd,
firstSection.Matches); firstSection.Matches);
section.Settings.copyFrom(lastSection.Settings); section.Settings.copyFrom(lastSection.Settings);
section.Matches.addAll(lastSection.Matches); section.Matches.addAll(lastSection.Matches);
sections.add(i, section); sections.add(i, section);
if (firstSectEnd > lastSection.End) { //Copy first section info to last as the lastSection initially cuts the firstSection in half if (firstSection.End > lastSection.End) { //Copy first section info to last as the lastSection initially cuts the firstSection in half
lastSection.Settings = FormatSettings.builder().build(); lastSection.Settings = FormatSettings.builder().build();
lastSection.Settings.copyFrom(firstSection.Settings); lastSection.Settings.copyFrom(firstSection.Settings);
} }
lastSection.Start = lastSectEnd + 1; firstSection.End = middleStart - 1;
lastSection.End = firstSectEnd; lastSection.Start = middleEnd + 1;
lastSection.End = lastSectEnd;
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) {
@ -149,11 +161,11 @@ public final class ChatFormatter {
DebugCommand.SendDebugMessage("To sections"); DebugCommand.SendDebugMessage("To sections");
if (!removeIfNeeded.test(firstSection)) { if (!removeIfNeeded.test(firstSection)) {
DebugCommand.SendDebugMessage(" 1:" + firstSection + ""); DebugCommand.SendDebugMessage(" 1:" + firstSection);
ChatFormatUtils.sendMessageWithPointer(str, firstSection.Start, firstSection.End); ChatFormatUtils.sendMessageWithPointer(str, firstSection.Start, firstSection.End);
} }
if (!removeIfNeeded.test(section)) { if (!removeIfNeeded.test(section)) {
DebugCommand.SendDebugMessage(" 2:" + section + ""); DebugCommand.SendDebugMessage(" 2:" + section);
ChatFormatUtils.sendMessageWithPointer(str, section.Start, section.End); ChatFormatUtils.sendMessageWithPointer(str, section.Start, section.End);
} }
if (!removeIfNeeded.test(lastSection)) { if (!removeIfNeeded.test(lastSection)) {
@ -163,21 +175,11 @@ public final class ChatFormatter {
i = 0; i = 0;
} }
sortSections(sections); sortSections(sections);
if (i == 0) continue;
for (int j = i - 1; j <= i + 1; j++) {
if (j < sections.size() && sections.get(j).End < sections.get(j).Start) {
DebugCommand.SendDebugMessage("Removing section: " + sections.get(j));
ChatFormatUtils.sendMessageWithPointer(str, sections.get(j).Start, sections.get(j).End);
sections.remove(j);
j--;
i = 0;
}
}
} }
} }
private static void applySections(String str, TellrawPart tp, ArrayList<FormattedSection> sections, ArrayList<int[]> remchars) { private static void applySections(String str, TextComponent.Builder tp, ArrayList<FormattedSection> sections, ArrayList<int[]> remchars) {
TellrawPart lasttp = null; TextComponent lasttp = null;
String lastlink = null; String lastlink = null;
for (FormattedSection section : sections) { for (FormattedSection section : sections) {
DebugCommand.SendDebugMessage("Applying section: " + section); DebugCommand.SendDebugMessage("Applying section: " + section);
@ -185,21 +187,9 @@ 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);
ChatFormatUtils.sendMessageWithPointer(str, start, end); ChatFormatUtils.sendMessageWithPointer(str, start, end);
/*DebugCommand.SendDebugMessage("RCS: "+remchars.stream().filter(rc -> rc[0] <= start && start <= rc[1]).count());
DebugCommand.SendDebugMessage("RCE: "+remchars.stream().filter(rc -> rc[0] <= end && end <= rc[1]).count());
DebugCommand.SendDebugMessage("RCI: "+remchars.stream().filter(rc -> start < rc[0] || rc[1] < end).count());*/
val rci = remchars.stream().filter(rc -> (rc[0] <= start && rc[1] >= start) val rci = remchars.stream().filter(rc -> (rc[0] <= start && rc[1] >= start)
|| (rc[0] >= start && rc[1] <= end) || (rc[0] >= start && rc[1] <= end)
|| (rc[0] <= end && rc[1] >= end)).sorted(Comparator.comparingInt(rc -> rc[0] * 10000 + rc[1])).toArray(int[][]::new); || (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;
if (rce.isPresent())
e = rce.get()[0] - 1;
DebugCommand.SendDebugMessage("After RC - Start: " + s + " - End: " + e);
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) + ")");
continue;
}*/
DebugCommand.SendDebugMessage("Applying RC: " + Arrays.stream(rci).map(Arrays::toString).collect(Collectors.joining(", ", "[", "]"))); DebugCommand.SendDebugMessage("Applying RC: " + Arrays.stream(rci).map(Arrays::toString).collect(Collectors.joining(", ", "[", "]")));
originaltext = str.substring(start, end + 1); originaltext = str.substring(start, end + 1);
val sb = new StringBuilder(originaltext); val sb = new StringBuilder(originaltext);
@ -212,50 +202,53 @@ public final class ChatFormatter {
} }
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
TellrawPart newtp = new TellrawPart("");
var settings = section.Settings; var settings = section.Settings;
DebugCommand.SendDebugMessage("Applying settings: " + settings); DebugCommand.SendDebugMessage("Applying settings: " + settings);
if (lasttp != null && hasSameDecorations(lasttp, settings) && Objects.equals(lastlink, settings.openlink)
&& settings.onmatch == null) { // The onmatch function can change the settings
DebugCommand.SendDebugMessage("This part has the same properties as the previous one, combining.");
lasttp = lasttp.content(lasttp.content() + originaltext);
continue; //Combine parts with the same properties
}
TextComponent.@NotNull Builder newtp = text();
if (settings.onmatch != null) if (settings.onmatch != null)
originaltext = settings.onmatch.apply(originaltext, settings, section); originaltext = settings.onmatch.apply(originaltext, settings, section);
if (settings.color != null) if (settings.color != null)
newtp.setColor(settings.color); newtp.color(settings.color);
if (settings.bold) if (settings.bold)
newtp.setBold(true); newtp.decorate(TextDecoration.BOLD);
if (settings.italic) if (settings.italic)
newtp.setItalic(true); newtp.decorate(TextDecoration.ITALIC);
if (settings.underlined) if (settings.underlined)
newtp.setUnderlined(true); newtp.decorate(TextDecoration.UNDERLINED);
if (settings.strikethrough) if (settings.strikethrough)
newtp.setStrikethrough(true); newtp.decorate(TextDecoration.STRIKETHROUGH);
if (settings.obfuscated) if (settings.obfuscated)
newtp.setObfuscated(true); newtp.decorate(TextDecoration.OBFUSCATED);
if (settings.openlink != null) if (settings.openlink != null)
openlink = settings.openlink; openlink = settings.openlink;
if (settings.hoverText != null) if (settings.hoverText != null)
newtp.setHoverEvent(TellrawEvent.create(TellrawEvent.HoverAction.SHOW_TEXT, settings.hoverText)); newtp.hoverEvent(hoverEvent(SHOW_TEXT, text(settings.hoverText)));
if (lasttp != null && newtp.getColor() == lasttp.getColor() if (lasttp != null) tp.append(lasttp);
&& newtp.isBold() == lasttp.isBold()
&& newtp.isItalic() == lasttp.isItalic()
&& newtp.isUnderlined() == lasttp.isUnderlined()
&& newtp.isStrikethrough() == lasttp.isStrikethrough()
&& newtp.isObfuscated() == lasttp.isObfuscated()
&& Objects.equals(openlink, lastlink)) {
DebugCommand.SendDebugMessage("This part has the same properties as the previous one, combining.");
lasttp.setText(lasttp.getText() + originaltext);
continue; //Combine parts with the same properties
}
lastlink = openlink; lastlink = openlink;
newtp.setText(originaltext); newtp.content(originaltext);
if (openlink != null && openlink.length() > 0) { if (openlink != null && openlink.length() > 0) {
newtp.setClickEvent(TellrawEvent.create(TellrawEvent.ClickAction.OPEN_URL, if (section.Matches.size() > 0)
(section.Matches.size() > 0 ? openlink.replace("$1", section.Matches.get(0)) : openlink))) openlink = openlink.replace("$1", section.Matches.get(0));
.setHoverEvent(TellrawEvent.create(TellrawEvent.HoverAction.SHOW_TEXT, newtp.clickEvent(clickEvent(OPEN_URL, openlink)).hoverEvent(hoverEvent(SHOW_TEXT, text("Click to open").color(NamedTextColor.BLUE)));
new TellrawPart("Click to open").setColor(Color.Blue)));
} }
tp.addExtra(newtp); lasttp = newtp.build();
lasttp = newtp;
} }
if (lasttp != null) tp.append(lasttp);
}
private static boolean hasSameDecorations(TextComponent c1, FormatSettings settings) {
return Objects.equals(c1.color(), settings.color)
&& c1.hasDecoration(TextDecoration.BOLD) == settings.bold
&& c1.hasDecoration(TextDecoration.ITALIC) == settings.italic
&& c1.hasDecoration(TextDecoration.UNDERLINED) == settings.underlined
&& c1.hasDecoration(TextDecoration.STRIKETHROUGH) == settings.strikethrough
&& c1.hasDecoration(TextDecoration.OBFUSCATED) == settings.obfuscated;
} }
private static void sortSections(ArrayList<FormattedSection> sections) { private static void sortSections(ArrayList<FormattedSection> sections) {

View file

@ -1,8 +1,8 @@
package buttondevteam.chat.components.formatter.formatting; package buttondevteam.chat.components.formatter.formatting;
import buttondevteam.lib.chat.Color;
import lombok.Builder; import lombok.Builder;
import lombok.Data; import lombok.Data;
import net.kyori.adventure.text.format.TextColor;
/** /**
* Describes how a matched section of the message should look. May be combined with other format settings. * Describes how a matched section of the message should look. May be combined with other format settings.
@ -15,7 +15,7 @@ public class FormatSettings {
boolean underlined; boolean underlined;
boolean strikethrough; boolean strikethrough;
boolean obfuscated; boolean obfuscated;
Color color; TextColor color;
ChatFormatter.TriFunc<String, FormatSettings, FormattedSection, String> onmatch; ChatFormatter.TriFunc<String, FormatSettings, FormattedSection, String> onmatch;
String openlink; String openlink;
String hoverText; String hoverText;
@ -27,7 +27,6 @@ public class FormatSettings {
if (field.getBoolean(settings)) if (field.getBoolean(settings))
field.setBoolean(this, true); //Set to true if either of them are true field.setBoolean(this, true); //Set to true if either of them are true
} else if (field.get(settings) != null) { } else if (field.get(settings) != null) {
//System.out.println("Setting " + field.getType() + " " + field.getName() + " from " + field.get(this) + " to " + field.get(settings));
field.set(this, field.get(settings)); field.set(this, field.get(settings));
} }
} }

View file

@ -1,7 +1,7 @@
package buttondevteam.chat.components.formatter.formatting; package buttondevteam.chat.components.formatter.formatting;
import buttondevteam.lib.architecture.ConfigData;
import buttondevteam.lib.architecture.IHaveConfig; import buttondevteam.lib.architecture.IHaveConfig;
import buttondevteam.lib.architecture.config.IConfigData;
import lombok.Getter; import lombok.Getter;
import lombok.RequiredArgsConstructor; import lombok.RequiredArgsConstructor;
@ -31,7 +31,7 @@ public abstract class MatchProviderBase implements MatchProvider {
resetSubclass(); resetSubclass();
} }
ConfigData<Boolean> enabled(IHaveConfig config) { IConfigData<Boolean> enabled(IHaveConfig config) {
return config.getData(name + ".enabled", true); return config.getData(name + ".enabled", true);
} }

View file

@ -12,7 +12,7 @@ public class StringMatchProvider extends MatchProviderBase {
@ToString.Exclude @ToString.Exclude
private final FormatSettings settings; private final FormatSettings settings;
private int nextIndex = 0; private int nextIndex = 0;
private boolean ignoreCase; private final boolean ignoreCase;
/** /**
* Matches the given strings in the order given * Matches the given strings in the order given

View file

@ -6,9 +6,9 @@ import java.io.Serializable;
public final class TellrawEvent<T extends TellrawEvent.Action> implements Serializable { public final class TellrawEvent<T extends TellrawEvent.Action> implements Serializable {
private static final long serialVersionUID = -1681364161210561505L; private static final long serialVersionUID = -1681364161210561505L;
private transient boolean hoverEvent; private final transient boolean hoverEvent;
private T action; private final T action;
private Object value; private final Object value;
private TellrawEvent(T action, String value) { private TellrawEvent(T action, String value) {
this.hoverEvent = action instanceof HoverAction; this.hoverEvent = action instanceof HoverAction;
@ -44,7 +44,7 @@ public final class TellrawEvent<T extends TellrawEvent.Action> implements Serial
public enum ClickAction implements Action { public enum ClickAction implements Action {
OPEN_URL("open_url"), RUN_COMMAND("run_command"), SUGGEST_COMMAND("suggest_command"); OPEN_URL("open_url"), RUN_COMMAND("run_command"), SUGGEST_COMMAND("suggest_command");
private String action; private final String action;
ClickAction(String action) { ClickAction(String action) {
this.action = action; this.action = action;
@ -58,8 +58,8 @@ public final class TellrawEvent<T extends TellrawEvent.Action> implements Serial
public enum HoverAction implements Action { public enum HoverAction implements Action {
SHOW_TEXT("show_text"), SHOW_ITEM("show_item"), SHOW_ACHIEVEMENT("show_achievement"), SHOW_ENTITY( SHOW_TEXT("show_text"), SHOW_ITEM("show_item"), SHOW_ACHIEVEMENT("show_achievement"), SHOW_ENTITY(
"show_entity"); "show_entity");
private String action; private final String action;
HoverAction(String action) { HoverAction(String action) {
this.action = action; this.action = action;

View file

@ -14,7 +14,7 @@ public final class TellrawPart implements Serializable {
private boolean underlined; private boolean underlined;
private boolean strikethrough; private boolean strikethrough;
private boolean obfuscated; private boolean obfuscated;
private List<TellrawPart> extra = new ArrayList<>(); private final List<TellrawPart> extra = new ArrayList<>();
private String text; private String text;
private TellrawEvent<TellrawEvent.HoverAction> hoverEvent; private TellrawEvent<TellrawEvent.HoverAction> hoverEvent;
private TellrawEvent<TellrawEvent.ClickAction> clickEvent; private TellrawEvent<TellrawEvent.ClickAction> clickEvent;

View file

@ -2,15 +2,13 @@ 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.Color; import buttondevteam.lib.chat.*;
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;
import java.util.Arrays; import java.util.Arrays;
import java.util.Optional; import java.util.Optional;
import java.util.stream.Stream;
@CommandClass(path = "u c", helpText = { @CommandClass(path = "u c", helpText = {
"Rainbow mode", "Rainbow mode",
@ -57,4 +55,9 @@ public class CCommand extends ICommand2MC {
} }
return true; return true;
} }
@CustomTabCompleteMethod(param = "color")
public Iterable<String> def() {
return Stream.concat(Stream.of("off"), Arrays.stream(Color.values()).map(Color::getName))::iterator;
}
} }

View file

@ -18,46 +18,47 @@ import java.util.concurrent.atomic.AtomicInteger;
import java.util.stream.Collectors; import java.util.stream.Collectors;
@CommandClass(helpText = { @CommandClass(helpText = {
"§6---- F Top ----", // "F Top", //
"Shows the respect leaderboard" // "Shows the respect leaderboard" //
}) })
public class FTopCommand extends ICommand2MC { public class FTopCommand extends ICommand2MC {
private final File playerdir = new File(TBMCPlayerBase.TBMC_PLAYERS_DIR); private final File playerdir = new File("TBMC/players/");
private ChatPlayer[] cached; private ChatPlayer[] cached;
private long lastcache = 0; private long lastcache = 0;
public boolean def(CommandSender sender, @Command2.OptionalArg int page) { @Command2.Subcommand
Bukkit.getScheduler().runTaskAsynchronously(PluginMain.Instance, () -> { public boolean def(CommandSender sender, @Command2.OptionalArg int page) {
if (cached == null || lastcache < System.nanoTime() - 60000000000L) { // 1m - (no guarantees of nanoTime's relation to 0, so we need the null check too) Bukkit.getScheduler().runTaskAsynchronously(PluginMain.Instance, () -> {
cached = Arrays.stream(Objects.requireNonNull(playerdir.listFiles())).sequential() if (cached == null || lastcache < System.nanoTime() - 60000000000L) { // 1m - (no guarantees of nanoTime's relation to 0, so we need the null check too)
.filter(f -> f.getName().length() > 4) cached = Arrays.stream(Objects.requireNonNull(playerdir.listFiles())).sequential()
.map(f -> { .filter(f -> f.getName().length() > 4)
try { .map(f -> {
return TBMCPlayerBase.getPlayer( try {
UUID.fromString(f.getName().substring(0, f.getName().length() - 4)), ChatPlayer.class); return TBMCPlayerBase.getPlayer(
} catch (Exception e) { UUID.fromString(f.getName().substring(0, f.getName().length() - 4)), ChatPlayer.class);
return null; } catch (Exception e) {
} return null;
}) }
.filter(Objects::nonNull) })
.sorted((cp1, cp2) -> Double.compare(cp2.getF(), cp1.getF())) .filter(Objects::nonNull)
.toArray(ChatPlayer[]::new); // TODO: Properly implement getting all players .sorted((cp1, cp2) -> Double.compare(cp2.getF(), cp1.getF()))
lastcache = System.nanoTime(); .toArray(ChatPlayer[]::new); // TODO: Properly implement getting all players
} lastcache = System.nanoTime();
int i; }
try { int i;
i = page<1?1:page; try {
i = page < 1 ? 1 : page;
} catch (Exception e) { } catch (Exception e) {
i = 1; i = 1;
} }
val ai = new AtomicInteger(); val ai = new AtomicInteger();
sender.sendMessage("§6---- Top Fs ----"); sender.sendMessage("§6---- Top Fs ----");
sender.sendMessage(Arrays.stream(cached).skip((i - 1) * 10).limit(i * 10) sender.sendMessage(Arrays.stream(cached).skip((i - 1) * 10L).limit(i * 10L)
.map(cp -> String.format("%d. %s - %f.2", ai.incrementAndGet(), cp.PlayerName().get(), cp.getF())) .map(cp -> String.format("%d. %s - %f.2", ai.incrementAndGet(), cp.getPlayerName(), cp.getF()))
.collect(Collectors.joining("\n"))); .collect(Collectors.joining("\n")));
}); });
return true; return true;
} }
} }

View file

@ -3,18 +3,19 @@ package buttondevteam.chat.components.fun;
import buttondevteam.chat.ChatPlayer; import buttondevteam.chat.ChatPlayer;
import buttondevteam.chat.PluginMain; import buttondevteam.chat.PluginMain;
import buttondevteam.core.component.channel.Channel; import buttondevteam.core.component.channel.Channel;
import buttondevteam.lib.ChromaUtils;
import buttondevteam.lib.TBMCChatEventBase; import buttondevteam.lib.TBMCChatEventBase;
import buttondevteam.lib.TBMCCommandPreprocessEvent; import buttondevteam.lib.TBMCCommandPreprocessEvent;
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.config.IConfigData;
import buttondevteam.lib.architecture.config.IListConfigData;
import buttondevteam.lib.chat.TBMCChatAPI; import buttondevteam.lib.chat.TBMCChatAPI;
import buttondevteam.lib.player.ChromaGamerBase; import buttondevteam.lib.player.ChromaGamerBase;
import buttondevteam.lib.player.TBMCPlayer; import buttondevteam.lib.player.TBMCPlayer;
import buttondevteam.lib.player.TBMCPlayerBase;
import com.google.common.collect.Lists;
import lombok.val; import lombok.val;
import org.bukkit.Bukkit; import org.bukkit.Bukkit;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player; import org.bukkit.entity.Player;
import org.bukkit.event.EventHandler; import org.bukkit.event.EventHandler;
import org.bukkit.event.EventPriority; import org.bukkit.event.EventPriority;
@ -36,34 +37,29 @@ 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 HashSet<CommandSender> Fs = new HashSet<>(); private final HashSet<ChromaGamerBase> 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;
private final Random random = new Random();
/** /**
* The strings that count as laughs, see unlol. * The strings that count as laughs, see unlol.
*/ */
private ConfigData<String[]> laughStrings() { private final IListConfigData<String> laughStrings = getConfig().getListData("laughStrings", Lists.newArrayList("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. * 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. * You can hover over a player's name to see their respect.
*/ */
private ConfigData<Boolean> respect() { private final IConfigData<Boolean> respect = getConfig().getData("respect", true);
return getConfig().getData("respect", true);
}
/** /**
* This is an inside joke on our server. * 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. * 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. * Which also blinds the laughing person for a few seconds. This action can only be performed once per laugh.
*/ */
private ConfigData<Boolean> unlol() { private final IConfigData<Boolean> unlol = getConfig().getData("unlol", true);
return getConfig().getData("unlol", true);
}
@Override @Override
protected void enable() { protected void enable() {
@ -72,7 +68,7 @@ public class FunComponent extends Component<PluginMain> implements Listener {
val pc = new PressCommand(); val pc = new PressCommand();
registerCommand(pc); registerCommand(pc);
registerListener(pc); registerListener(pc);
registerCommand(command=new UnlolCommand(unlolTarget)); registerCommand(command = new UnlolCommand(unlolTarget));
registerListener(this); registerListener(this);
registerCommand(new FTopCommand()); registerCommand(new FTopCommand());
registerCommand(new OpmeCommand()); registerCommand(new OpmeCommand());
@ -85,20 +81,21 @@ public class FunComponent extends Component<PluginMain> implements Listener {
} }
public void onChat(CommandSender sender, TBMCChatEventBase event, String message) { public void onChat(ChromaGamerBase sender, TBMCChatEventBase event, String message) {
if (ActiveF && !Fs.contains(sender) && message.equalsIgnoreCase("F")) if (ActiveF && !Fs.contains(sender) && message.equalsIgnoreCase("F"))
Fs.add(sender); Fs.add(sender);
if (unlol().get()) { if (unlol.get()) {
String msg = message.toLowerCase(); String msg = message.toLowerCase();
val lld = new UnlolCommand.LastlolData(sender, event, System.nanoTime()); val lld = new UnlolCommand.LastlolData(sender, event, System.nanoTime());
boolean add; boolean add = msg.contains("lol");
if (add = msg.contains("lol")) if (add)
lld.setLolornot(true); lld.setLolornot(true);
else { else {
String[] laughs = laughStrings().get(); val laughs = laughStrings.get();
for (String laugh : laughs) { for (String laugh : laughs) {
if (add = msg.contains(laugh)) { add = msg.contains(laugh);
if (add) {
lld.setLolornot(false); lld.setLolornot(false);
break; break;
} }
@ -112,13 +109,13 @@ public class FunComponent extends Component<PluginMain> implements Listener {
@EventHandler @EventHandler
public void onPlayerDeath(PlayerDeathEvent e) { public void onPlayerDeath(PlayerDeathEvent e) {
// MinigamePlayer mgp = Minigames.plugin.pdata.getMinigamePlayer(e.getEntity()); // MinigamePlayer mgp = Minigames.plugin.pdata.getMinigamePlayer(e.getEntity());
if (e.getDeathMessage().length() > 0 && respect().get() && new Random().nextBoolean()) { // Don't store Fs for NPCs if (e.getDeathMessage().length() > 0 && respect.get() && random.nextBoolean()) { // Don't store Fs for NPCs
Runnable tt = () -> { Runnable tt = () -> {
if (ActiveF) { if (ActiveF) {
ActiveF = false; ActiveF = false;
if (FPlayer != null && FPlayer.FCount().get() < Integer.MAX_VALUE - 1) if (FPlayer != null && FPlayer.FCount.get() < Integer.MAX_VALUE - 1)
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();
@ -131,8 +128,8 @@ public class FunComponent extends Component<PluginMain> implements Listener {
ActiveF = true; ActiveF = true;
Fs.clear(); Fs.clear();
FPlayer = TBMCPlayer.getPlayer(e.getEntity().getUniqueId(), ChatPlayer.class); FPlayer = TBMCPlayer.getPlayer(e.getEntity().getUniqueId(), ChatPlayer.class);
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);
Ftask = Bukkit.getScheduler().runTaskLaterAsynchronously(PluginMain.Instance, tt, 15 * 20); Ftask = Bukkit.getScheduler().runTaskLaterAsynchronously(PluginMain.Instance, tt, 15 * 20);
} }
@ -140,14 +137,14 @@ public class FunComponent extends Component<PluginMain> implements Listener {
@EventHandler @EventHandler
public void onPlayerLeave(PlayerQuitEvent event) { public void onPlayerLeave(PlayerQuitEvent event) {
if (unlol().get()) if (unlol.get())
command.Lastlol.values().removeIf(lld -> lld.getLolowner().equals(event.getPlayer())); command.Lastlol.values().removeIf(lld -> lld.getLolowner().equals(ChromaGamerBase.getFromSender(event.getPlayer())));
} }
@EventHandler(priority = EventPriority.LOWEST) @EventHandler(priority = EventPriority.LOWEST)
public void onCommandPreprocess(TBMCCommandPreprocessEvent event) { public void onCommandPreprocess(TBMCCommandPreprocessEvent event) {
if (event.isCancelled()) return; if (event.isCancelled()) return;
if (!unlol().get()) return; if (!unlol.get()) return;
final String cmd = event.getMessage(); final String cmd = event.getMessage();
// We don't care if we have arguments // We don't care if we have arguments
if (cmd.toLowerCase().startsWith("/un")) { if (cmd.toLowerCase().startsWith("/un")) {
@ -155,7 +152,14 @@ public class FunComponent extends Component<PluginMain> implements Listener {
if (ht.getName().equalsIgnoreCase(cmd)) if (ht.getName().equalsIgnoreCase(cmd))
return; return;
} }
if (PluginMain.permission.has(event.getSender(), "chroma.unanything")) { val user = event.getSender();
if (!(user instanceof TBMCPlayerBase)) {
// TODO: Cross-platform permission check; console is not supported here
user.sendMessage("§cError: You must be a player to use this command.");
return;
}
val player = ((TBMCPlayerBase) user).getPlayer();
if (player != null && PluginMain.permission.has(player, "chroma.unanything")) {
event.setCancelled(true); event.setCancelled(true);
int index = cmd.lastIndexOf(' '); int index = cmd.lastIndexOf(' ');
if (index == -1) { if (index == -1) {
@ -168,10 +172,9 @@ public class FunComponent extends Component<PluginMain> implements Listener {
event.getSender().sendMessage("§cError: Player not found. (/un" + s + " <player>)"); event.getSender().sendMessage("§cError: Player not found. (/un" + s + " <player>)");
return; return;
} }
val user = ChromaGamerBase.getFromSender(event.getSender());
target.addPotionEffect(new PotionEffect(PotionEffectType.BLINDNESS, 10 * 20, 5, false, false)); target.addPotionEffect(new PotionEffect(PotionEffectType.BLINDNESS, 10 * 20, 5, false, false));
val chan = user.channel().get(); val chan = user.getChannel().get();
TBMCChatAPI.SendSystemMessage(chan, chan.getRTR(event.getSender()), ChromaUtils.getDisplayName(event.getSender()) + " un" + s TBMCChatAPI.SendSystemMessage(chan, chan.getRTR(event.getSender()), event.getSender().getName() + " un" + s
+ "'d " + target.getDisplayName(), unlolTarget); + "'d " + target.getDisplayName(), unlolTarget);
} }
} }

View file

@ -1,6 +1,7 @@
package buttondevteam.chat.components.fun; package buttondevteam.chat.components.fun;
import buttondevteam.core.component.channel.Channel; import buttondevteam.core.component.channel.Channel;
import buttondevteam.core.component.restart.RestartComponent;
import buttondevteam.core.component.restart.ScheduledRestartCommand; import buttondevteam.core.component.restart.ScheduledRestartCommand;
import buttondevteam.lib.ChromaUtils; import buttondevteam.lib.ChromaUtils;
import buttondevteam.lib.ScheduledServerRestartEvent; import buttondevteam.lib.ScheduledServerRestartEvent;
@ -8,13 +9,18 @@ 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.TBMCChatAPI; import buttondevteam.lib.chat.TBMCChatAPI;
import org.bukkit.Bukkit;
import org.bukkit.command.CommandSender; import org.bukkit.command.CommandSender;
import org.bukkit.event.EventHandler; import org.bukkit.event.EventHandler;
import org.bukkit.event.Listener; import org.bukkit.event.Listener;
import java.util.HashSet; import java.util.HashSet;
@CommandClass @CommandClass(helpText = {
"Press",
"This command resets the restart countdown if it's active. Can only be used once per player.",
"It's based on Reddit's /r/thebutton"
})
public class PressCommand extends ICommand2MC implements Listener { public class PressCommand extends ICommand2MC implements Listener {
private HashSet<CommandSender> pressers; //Will be cleared with this class on shutdown/disable private HashSet<CommandSender> pressers; //Will be cleared with this class on shutdown/disable
private ScheduledRestartCommand command; private ScheduledRestartCommand command;
@ -31,7 +37,7 @@ public class PressCommand extends ICommand2MC implements Listener {
return; return;
} }
pressers.add(sender); pressers.add(sender);
TBMCChatAPI.SendSystemMessage(Channel.GlobalChat, Channel.RecipientTestResult.ALL, String.format("§b-- %s §bpressed at %.0fs", ChromaUtils.getDisplayName(sender), command.getRestartCounter() / 20f), command.getComponent().getRestartBroadcast()); TBMCChatAPI.SendSystemMessage(Channel.globalChat, Channel.RecipientTestResult.ALL, String.format("§b-- %s §bpressed at %.0fs", ChromaUtils.getDisplayName(sender), command.getRestartCounter() / 20f), ((RestartComponent) command.getComponent()).getRestartBroadcast());
command.setRestartCounter(startTicks); command.setRestartCounter(startTicks);
} }
@ -40,5 +46,7 @@ public class PressCommand extends ICommand2MC implements Listener {
command = event.getCommand(); command = event.getCommand();
pressers = new HashSet<>(); pressers = new HashSet<>();
startTicks = event.getRestartTicks(); startTicks = event.getRestartTicks();
if (Bukkit.getOnlinePlayers().size() > 0)
TBMCChatAPI.SendSystemMessage(Channel.globalChat, Channel.RecipientTestResult.ALL, "§b-- Do /press to reset the timer. You may only press once.", ((RestartComponent) command.getComponent()).getRestartBroadcast());
} }
} }

View file

@ -1,17 +1,16 @@
package buttondevteam.chat.components.fun; package buttondevteam.chat.components.fun;
import buttondevteam.core.component.channel.Channel; import buttondevteam.core.component.channel.Channel;
import buttondevteam.lib.ChromaUtils;
import buttondevteam.lib.TBMCChatEventBase; import buttondevteam.lib.TBMCChatEventBase;
import buttondevteam.lib.TBMCSystemChatEvent; import buttondevteam.lib.TBMCSystemChatEvent;
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.TBMCChatAPI; import buttondevteam.lib.chat.TBMCChatAPI;
import buttondevteam.lib.player.ChromaGamerBase;
import buttondevteam.lib.player.TBMCPlayerBase;
import lombok.Data; import lombok.Data;
import lombok.RequiredArgsConstructor; import lombok.RequiredArgsConstructor;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player;
import org.bukkit.potion.PotionEffect; import org.bukkit.potion.PotionEffect;
import org.bukkit.potion.PotionEffectType; import org.bukkit.potion.PotionEffectType;
@ -20,8 +19,8 @@ import java.util.HashMap;
import java.util.Map; import java.util.Map;
@CommandClass(modOnly = false, helpText = { @CommandClass(modOnly = false, helpText = {
"§6---- Unlol/unlaugh ----", "Unlol/unlaugh",
"This command is based on a joke between NorbiPeti and Ghostise", "This command is based on an inside joke",
"It will make the last person saying one of the recognized laugh strings blind for a few seconds", "It will make the last person saying one of the recognized laugh strings blind for a few seconds",
"Note that you can only unlaugh laughs that weren't unlaughed before" "Note that you can only unlaugh laughs that weren't unlaughed before"
}) })
@ -33,18 +32,18 @@ public final class UnlolCommand extends ICommand2MC {
private final TBMCSystemChatEvent.BroadcastTarget target; private final TBMCSystemChatEvent.BroadcastTarget target;
@Command2.Subcommand @Command2.Subcommand
public boolean def(CommandSender sender) { public boolean def(ChromaGamerBase sender) {
LastlolData lol = Lastlol.values().stream().filter(lld -> lld.Chatevent.shouldSendTo(sender)) LastlolData lol = Lastlol.values().stream().filter(lld -> lld.Chatevent.shouldSendTo(sender))
.max(Comparator.comparingLong(lld -> lld.Loltime)).orElse(null); .max(Comparator.comparingLong(lld -> lld.Loltime)).orElse(null);
if (lol == null) if (lol == null)
return true; return true;
if (lol.Lolowner instanceof Player) if (lol.Lolowner instanceof TBMCPlayerBase) {
((Player) lol.Lolowner) var player = ((TBMCPlayerBase) lol.Lolowner).getPlayer();
.addPotionEffect(new PotionEffect(PotionEffectType.BLINDNESS, 2 * 20, 5, false, false)); if (player != null)
String msg = ChromaUtils.getDisplayName(sender) player.addPotionEffect(new PotionEffect(PotionEffectType.BLINDNESS, 2 * 20, 5, false, false));
+ (lol.Lolornot ? " unlolled " : " unlaughed ") }
+ ChromaUtils.getDisplayName(lol.Lolowner); String msg = sender.getName() + (lol.Lolornot ? " unlolled " : " unlaughed ") + lol.Lolowner.getName();
TBMCChatAPI.SendSystemMessage(Channel.GlobalChat, Channel.RecipientTestResult.ALL, msg, target); TBMCChatAPI.SendSystemMessage(Channel.globalChat, Channel.RecipientTestResult.ALL, msg, target);
Lastlol.remove(lol.Chatevent.getChannel()); Lastlol.remove(lol.Chatevent.getChannel());
return true; return true;
} }
@ -52,7 +51,7 @@ public final class UnlolCommand extends ICommand2MC {
@Data @Data
public static class LastlolData { public static class LastlolData {
private boolean Lolornot; private boolean Lolornot;
private final CommandSender Lolowner; private final ChromaGamerBase Lolowner;
private final TBMCChatEventBase Chatevent; private final TBMCChatEventBase Chatevent;
private final long Loltime; private final long Loltime;
} }

View file

@ -11,7 +11,6 @@ import com.palmergames.bukkit.towny.object.Town;
import org.bukkit.ChatColor; import org.bukkit.ChatColor;
import org.bukkit.entity.Player; import org.bukkit.entity.Player;
import java.util.ArrayList;
import java.util.Arrays; import java.util.Arrays;
import java.util.stream.Collectors; import java.util.stream.Collectors;
@ -28,8 +27,8 @@ public class NColorCommand extends UCommandBase {
Resident res; Resident res;
Town town; Town town;
try { try {
if ((res = TownyComponent.TU.getResidentMap().get(player.getName().toLowerCase())) == null || !res.hasTown() if ((res = TownyComponent.dataSource.getResident(player.getName())) == null || !res.hasTown()
|| (town = res.getTown()) == null) { || (town = res.getTown()) == null) {
player.sendMessage("§cYou need to be in a town."); player.sendMessage("§cYou need to be in a town.");
return true; return true;
} }
@ -41,7 +40,7 @@ public class NColorCommand extends UCommandBase {
//Don't add ~ for nicknames //Don't add ~ for nicknames
if (!nameWithLines.replace("|", "").replace(":", "").equalsIgnoreCase(name)) { if (!nameWithLines.replace("|", "").replace(":", "").equalsIgnoreCase(name)) {
player.sendMessage("§cThe name you gave doesn't match your name. Make sure to use " player.sendMessage("§cThe name you gave doesn't match your name. Make sure to use "
+ name + "§c with added vertical lines (|) or colons (:)."); + name + "§c with added vertical lines (|) or colons (:).");
return true; return true;
} }
String[] nameparts = nameWithLines.split("[|:]"); String[] nameparts = nameWithLines.split("[|:]");
@ -50,22 +49,31 @@ public class NColorCommand extends UCommandBase {
player.sendMessage("§cYour town doesn't have a color set. The town mayor can set it using /u towncolor."); player.sendMessage("§cYour town doesn't have a color set. The town mayor can set it using /u towncolor.");
return true; return true;
} }
if (nameparts.length < towncolors.length + 1) { //+1: Nation color var component = TownColorComponent.getComponent();
byte nationColors = (byte) (component.useNationColors.get() ? 1 : 0);
if (nameparts.length < towncolors.length + nationColors) { //+1: Nation color
player.sendMessage("§cYou need more vertical lines (|) or colons (:) in your name. (Should have " + (towncolors.length - 1 + 1) + ")"); //Nation color player.sendMessage("§cYou need more vertical lines (|) or colons (:) in your name. (Should have " + (towncolors.length - 1 + 1) + ")"); //Nation color
return true; return true;
} }
if (nameparts.length > (towncolors.length + 1) * 2) { if (nameparts.length > (towncolors.length + nationColors) * 2) {
player.sendMessage("§cYou have waay too many vertical lines (|) or colons (:) in your name. (Should have " + (towncolors.length - 1 + 1) + ")"); player.sendMessage("§cYou have waay too many vertical lines (|) or colons (:) in your name. (Should have " + (towncolors.length - 1 + 1) + ")");
return true; return true;
} }
if (nameparts.length > towncolors.length + 1) { if (nameparts.length > towncolors.length + nationColors) {
player.sendMessage("§cYou have too many vertical lines (|) or colons (:) in your name. (Should have " + (towncolors.length - 1 + 1) + ")"); player.sendMessage("§cYou have too many vertical lines (|) or colons (:) in your name. (Should have " + (towncolors.length - 1 + 1) + ")");
return true; return true;
} }
ChatPlayer.getPlayer(player.getUniqueId(), ChatPlayer.class).NameColorLocations() var cp = ChatPlayer.getPlayer(player.getUniqueId(), ChatPlayer.class);
.set(new ArrayList<>(Arrays.stream(nameparts).map(String::length).collect(Collectors.toList()))); // No byte[], no TIntArrayList var list = Arrays.stream(nameparts).map(String::length).collect(Collectors.toList());
TownColorComponent.updatePlayerColors(player); if (list.contains(0)) {
player.sendMessage("§bName colors set: " + player.getDisplayName()); player.sendMessage("§cAll colors need to be represented in your name. (Use as Test|name|123 instead of |Testname123|)");
return true;
}
var clist = cp.NameColorLocations.get(); // No byte[], no TIntArrayList
clist.clear();
clist.addAll(list);
TownColorComponent.updatePlayerColors(player, cp);
player.sendMessage("§bName colors set: " + player.getDisplayName());
return true; return true;
} }
} }

View file

@ -1,10 +1,11 @@
package buttondevteam.chat.components.towncolors; package buttondevteam.chat.components.towncolors;
import buttondevteam.chat.commands.ucmds.UCommandBase; import buttondevteam.chat.commands.ucmds.UCommandBase;
import buttondevteam.chat.components.towncolors.admin.TownColorCommand;
import buttondevteam.chat.components.towny.TownyComponent; import buttondevteam.chat.components.towny.TownyComponent;
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.CustomTabCompleteMethod;
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;
@ -19,20 +20,23 @@ import org.bukkit.entity.Player;
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) {
Resident res; String msg = "§cYou need to be the king of a nation to set it's colors.";
if (!(TownyComponent.TU.getResidentMap().containsKey(player.getName().toLowerCase())
&& (res = TownyComponent.TU.getResidentMap().get(player.getName().toLowerCase())).isKing())) {
player.sendMessage("§cYou need to be the king of a nation to set it's colors.");
return true;
}
final Nation n;
try { try {
n = res.getTown().getNation(); Resident res = TownyComponent.dataSource.getResident(player.getName());
if (!res.isKing()) {
player.sendMessage(msg);
return true;
}
final Nation n = res.getTown().getNation();
return buttondevteam.chat.components.towncolors.admin.NationColorCommand.SetNationColor(player, n, color);
} catch (NotRegisteredException e) { } catch (NotRegisteredException e) {
TBMCCoreAPI.SendException("Failed to set nation color for player " + player + "!", e); player.sendMessage(msg);
player.sendMessage("§cCouldn't find your town/nation... Error reported.");
return true; return true;
} }
return buttondevteam.chat.components.towncolors.admin.NationColorCommand.SetNationColor(player, n, color); }
@CustomTabCompleteMethod(param = "color")
public Iterable<String> def() {
return TownColorCommand.tabcompleteColor();
} }
} }

View file

@ -2,9 +2,9 @@ package buttondevteam.chat.components.towncolors;
import buttondevteam.chat.commands.ucmds.UCommandBase; import buttondevteam.chat.commands.ucmds.UCommandBase;
import buttondevteam.chat.components.towny.TownyComponent; import buttondevteam.chat.components.towny.TownyComponent;
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.CustomTabCompleteMethod;
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;
@ -17,32 +17,35 @@ import org.bukkit.entity.Player;
"This command allows setting a color for a town.", // "This command allows setting a color for a town.", //
"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 })
@RequiredArgsConstructor @RequiredArgsConstructor
public class TownColorCommand extends UCommandBase { public class TownColorCommand extends UCommandBase {
private final TownColorComponent component; private final TownColorComponent component;
@Command2.Subcommand @Command2.Subcommand
public boolean def(Player player, String... colornames) { public boolean def(Player player, String... colornames) {
Resident res; String msg = "§cYou need to be the mayor of a town to set its colors.";
if (!(TownyComponent.TU.getResidentMap().containsKey(player.getName().toLowerCase())
&& (res = TownyComponent.TU.getResidentMap().get(player.getName().toLowerCase())).isMayor())) {
player.sendMessage("§cYou need to be the mayor of a town to set its colors.");
return true;
}
val cc = component.colorCount().get();
if (colornames.length > cc) {
player.sendMessage("You can only use " + cc + " color" + (cc > 1 ? "s" : "") + ".");
return true;
}
final Town t;
try { try {
t = res.getTown(); Resident res = TownyComponent.dataSource.getResident(player.getName());
if (!res.isMayor()) {
player.sendMessage(msg);
return true;
}
val cc = component.colorCount.get();
if (colornames.length > cc) {
player.sendMessage("You can only use " + cc + " color" + (cc > 1 ? "s" : "") + ".");
return true;
}
final Town t = res.getTown();
return buttondevteam.chat.components.towncolors.admin.TownColorCommand.SetTownColor(player, t, colornames);
} catch (NotRegisteredException e) { } catch (NotRegisteredException e) {
TBMCCoreAPI.SendException("Failed to set town color for player " + player + "!", e); player.sendMessage(msg);
player.sendMessage("§cCouldn't find your town... Error reported.");
return true; return true;
} }
return buttondevteam.chat.components.towncolors.admin.TownColorCommand.SetTownColor(player, t, colornames); }
@CustomTabCompleteMethod(param = "colornames")
public Iterable<String> def() {
return buttondevteam.chat.components.towncolors.admin.TownColorCommand.tabcompleteColor();
} }
} }

View file

@ -8,12 +8,13 @@ import buttondevteam.core.ComponentManager;
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.ComponentMetadata;
import buttondevteam.lib.architecture.ConfigData; import buttondevteam.lib.architecture.config.IConfigData;
import buttondevteam.lib.chat.Color; import buttondevteam.lib.chat.Color;
import buttondevteam.lib.player.TBMCPlayerJoinEvent; import buttondevteam.lib.player.TBMCPlayer;
import com.earth2me.essentials.User; import com.earth2me.essentials.User;
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 lombok.Getter; import lombok.Getter;
import lombok.val; import lombok.val;
import org.bukkit.Bukkit; import org.bukkit.Bukkit;
@ -21,7 +22,9 @@ import org.bukkit.ChatColor;
import org.bukkit.configuration.ConfigurationSection; import org.bukkit.configuration.ConfigurationSection;
import org.bukkit.entity.Player; import org.bukkit.entity.Player;
import org.bukkit.event.EventHandler; import org.bukkit.event.EventHandler;
import org.bukkit.event.EventPriority;
import org.bukkit.event.Listener; import org.bukkit.event.Listener;
import org.bukkit.event.player.PlayerJoinEvent;
import org.bukkit.plugin.Plugin; import org.bukkit.plugin.Plugin;
import org.dynmap.towny.DTBridge; import org.dynmap.towny.DTBridge;
@ -41,26 +44,22 @@ public class TownColorComponent extends Component<PluginMain> implements Listene
/** /**
* Names lowercased * Names lowercased
*/ */
public static Map<String, Color[]> TownColors = new HashMap<>(); public static final Map<String, Color[]> TownColors = new HashMap<>();
/** /**
* Names lowercased - nation color gets added to town colors when needed * Names lowercased - nation color gets added to town colors when needed
*/ */
public static Map<String, Color> NationColor = new HashMap<>(); public static final 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. * The amount of town colors allowed. If more than one is used (or nation colors are enabled), players can change how many letters to be in a specific color using /u ncolor.
*/ */
public ConfigData<Byte> colorCount() { public final IConfigData<Byte> colorCount = 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. * 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. * They can change how much of each color they want with this as well.
*/ */
public ConfigData<Boolean> useNationColors() { public final IConfigData<Boolean> useNationColors = getConfig().getData("useNationColors", true);
return getConfig().getData("useNationColors", true);
}
@Getter @Getter
private static TownColorComponent component; private static TownColorComponent component;
@ -72,7 +71,7 @@ public class TownColorComponent extends Component<PluginMain> implements Listene
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))));
boolean usenc = useNationColors().get(); boolean usenc = useNationColors.get();
Consumer<ConfigurationSection> loadNC = ncs -> Consumer<ConfigurationSection> loadNC = ncs ->
TownColorComponent.NationColor.putAll(ncs.getValues(true).entrySet().stream() TownColorComponent.NationColor.putAll(ncs.getValues(true).entrySet().stream()
.collect(Collectors.toMap(Map.Entry::getKey, v -> Color.valueOf((String) v.getValue())))); .collect(Collectors.toMap(Map.Entry::getKey, v -> Color.valueOf((String) v.getValue()))));
@ -85,17 +84,17 @@ public class TownColorComponent extends Component<PluginMain> implements Listene
loadNC.accept(ncs); loadNC.accept(ncs);
} }
TownColors.keySet().removeIf(t -> !TownyComponent.TU.getTownsMap().containsKey(t)); // Removes town colors for deleted/renamed towns TownColors.keySet().removeIf(t -> TownyComponent.dataSource.getTown(t) == null); // Removes town colors for deleted/renamed towns
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.dataSource.getNation(n) == null); // Removes nation colors for deleted/renamed nations
initDynmap(); initDynmap();
registerCommand(new TownColorCommand(this)); registerCommand(new TownColorCommand(this));
if (useNationColors().get()) if (useNationColors.get())
registerCommand(new NationColorCommand()); registerCommand(new NationColorCommand());
registerCommand(new buttondevteam.chat.components.towncolors.admin.TownColorCommand()); registerCommand(new buttondevteam.chat.components.towncolors.admin.TownColorCommand());
if (useNationColors().get()) if (useNationColors.get())
registerCommand(new buttondevteam.chat.components.towncolors.admin.NationColorCommand()); registerCommand(new buttondevteam.chat.components.towncolors.admin.NationColorCommand());
registerCommand(new TCCount()); registerCommand(new TCCount());
registerCommand(new NColorCommand()); registerCommand(new NColorCommand());
@ -107,9 +106,10 @@ public class TownColorComponent extends Component<PluginMain> implements Listene
protected void disable() { protected void disable() {
getConfig().getConfig().createSection("towncolors", TownColors.entrySet().stream().collect(Collectors.toMap(Map.Entry::getKey, getConfig().getConfig().createSection("towncolors", TownColors.entrySet().stream().collect(Collectors.toMap(Map.Entry::getKey,
v -> Arrays.stream(v.getValue()).map(Enum::toString).toArray(String[]::new)))); v -> Arrays.stream(v.getValue()).map(Enum::toString).toArray(String[]::new))));
if (useNationColors().get()) if (useNationColors.get())
getConfig().getConfig().createSection("nationcolors", NationColor.entrySet().stream().collect(Collectors.toMap(Map.Entry::getKey, getConfig().getConfig().createSection("nationcolors", NationColor.entrySet().stream().collect(Collectors.toMap(Map.Entry::getKey,
v -> v.getValue().toString()))); v -> v.getValue().toString())));
getConfig().signalChange();
} }
private void initDynmap() { private void initDynmap() {
@ -119,16 +119,16 @@ public class TownColorComponent extends Component<PluginMain> implements Listene
return; return;
for (val entry : TownColors.entrySet()) { for (val entry : TownColors.entrySet()) {
try { try {
val town = TownyComponent.TU.getTownsMap().get(entry.getKey()); val town = TownyComponent.dataSource.getTown(entry.getKey());
Nation nation; Nation nation;
Color nc; Color nc;
if (!useNationColors().get()) if (!useNationColors.get())
nc = null; nc = null;
else if (!town.hasNation() || (nation = town.getNation()) == null || (nc = NationColor.get(nation.getName().toLowerCase())) == null) else if (!town.hasNation() || (nation = town.getNation()) == null || (nc = NationColor.get(nation.getName().toLowerCase())) == null)
nc = Color.White; nc = Color.White;
setTownColor(dtp, buttondevteam.chat.components.towncolors.admin.TownColorCommand.getTownNameCased(entry.getKey()), entry.getValue(), nc); setTownColor(dtp, buttondevteam.chat.components.towncolors.admin.TownColorCommand.getTownNameCased(entry.getKey()), entry.getValue(), nc);
} catch (Exception e) { } catch (Exception e) {
TBMCCoreAPI.SendException("Error while setting town color for town " + entry.getKey() + "!", e); TBMCCoreAPI.SendException("Error while setting town color for town " + entry.getKey() + "!", e, this);
} }
} }
}); });
@ -147,7 +147,7 @@ public class TownColorComponent extends Component<PluginMain> implements Listene
DTBridge.setTownColor(dtp, town, c2i.apply(nationcolor == null ? colors[0] : nationcolor), DTBridge.setTownColor(dtp, town, c2i.apply(nationcolor == null ? colors[0] : nationcolor),
c2i.apply(colors.length > 1 && nationcolor != null ? colors[1] : colors[0])); c2i.apply(colors.length > 1 && nationcolor != null ? colors[1] : colors[0]));
} catch (Exception e) { } catch (Exception e) {
TBMCCoreAPI.SendException("Failed to set town color for town " + town + "!", e); TBMCCoreAPI.SendException("Failed to set town color for town " + town + "!", e, component);
} }
} }
@ -156,7 +156,7 @@ public class TownColorComponent extends Component<PluginMain> implements Listene
if (nickname.contains("~")) //StartsWith doesn't work because of color codes if (nickname.contains("~")) //StartsWith doesn't work because of color codes
nickname = nickname.replace("~", ""); //It gets stacked otherwise nickname = nickname.replace("~", ""); //It gets stacked otherwise
String name = ChatColor.stripColor(nickname); //Enforce "town colors" on non-members String name = ChatColor.stripColor(nickname); //Enforce "town colors" on non-members
val res = TownyComponent.TU.getResidentMap().get(player.getName().toLowerCase()); Resident res = TownyComponent.dataSource.getResident(player.getName());
if (res == null || !res.hasTown()) if (res == null || !res.hasTown())
return name; return name;
try { try {
@ -178,8 +178,8 @@ public class TownColorComponent extends Component<PluginMain> implements Listene
len = name.length() / (clrs.length+1); len = name.length() / (clrs.length+1);
else else
len = name.length() / clrs.length;*/ len = name.length() / clrs.length;*/
boolean usenc = component.useNationColors().get(); boolean usenc = component.useNationColors.get();
val nclar = cp.NameColorLocations().get(); val nclar = cp.NameColorLocations.get();
int[] ncl = nclar == null ? null : nclar.stream().mapToInt(Integer::intValue).toArray(); int[] ncl = nclar == null ? null : nclar.stream().mapToInt(Integer::intValue).toArray();
if (ncl != null && (Arrays.stream(ncl).sum() != name.length() || ncl.length != clrs.length + (usenc ? 1 : 0))) //+1: Nation color if (ncl != null && (Arrays.stream(ncl).sum() != name.length() || ncl.length != clrs.length + (usenc ? 1 : 0))) //+1: Nation color
ncl = null; // Reset if name length changed ncl = null; // Reset if name length changed
@ -201,14 +201,14 @@ public class TownColorComponent extends Component<PluginMain> implements Listene
/** /**
* Checks if the component is enabled * Checks if the component is enabled
*/ */
public static void updatePlayerColors(Player player) { //Probably while ingame (/u ncolor) public static void updatePlayerColors(Player player) { //Probably while ingame (/u ncolor - not anymore)
updatePlayerColors(player, ChatPlayer.getPlayer(player.getUniqueId(), ChatPlayer.class)); updatePlayerColors(player, ChatPlayer.getPlayer(player.getUniqueId(), ChatPlayer.class));
} }
/** /**
* Checks if the component is enabled * Checks if the component is enabled
*/ */
private static void updatePlayerColors(Player player, ChatPlayer cp) { //Probably at join - nop, nicknames public static void updatePlayerColors(Player player, ChatPlayer cp) { //Probably at join - nop, nicknames
if (!ComponentManager.isEnabled(TownColorComponent.class)) if (!ComponentManager.isEnabled(TownColorComponent.class))
return; return;
User user = PluginMain.essentials.getUser(player); User user = PluginMain.essentials.getUser(player);
@ -217,8 +217,8 @@ public class TownColorComponent extends Component<PluginMain> implements Listene
cp.FlairUpdate(); //Update in list cp.FlairUpdate(); //Update in list
} }
@EventHandler @EventHandler(priority = EventPriority.HIGHEST)
public void onPlayerJoin(TBMCPlayerJoinEvent event) { public void onPlayerJoin(PlayerJoinEvent event) {
updatePlayerColors(event.getPlayer(), event.GetPlayer().asPluginPlayer(ChatPlayer.class)); updatePlayerColors(event.getPlayer(), TBMCPlayer.getPlayer(event.getPlayer().getUniqueId(), ChatPlayer.class));
} }
} }

View file

@ -61,7 +61,7 @@ public class TownyListener implements Listener {
@EventHandler @EventHandler
public void onNationRename(RenameNationEvent event) { public void onNationRename(RenameNationEvent event) {
if (!TownColorComponent.getComponent().useNationColors().get()) return; if (!TownColorComponent.getComponent().useNationColors.get()) return;
val clrs = TownColorComponent.NationColor.remove(event.getOldName().toLowerCase()); val clrs = TownColorComponent.NationColor.remove(event.getOldName().toLowerCase());
if (clrs != null) if (clrs != null)
TownColorComponent.NationColor.put(event.getNation().getName().toLowerCase(), clrs); TownColorComponent.NationColor.put(event.getNation().getName().toLowerCase(), clrs);
@ -69,25 +69,25 @@ public class TownyListener implements Listener {
@EventHandler //Gets called on town load as well @EventHandler //Gets called on town load as well
public void onNationJoin(NationAddTownEvent event) { public void onNationJoin(NationAddTownEvent event) {
if (!TownColorComponent.getComponent().useNationColors().get()) return; if (!TownColorComponent.getComponent().useNationColors.get()) return;
updateTownMembers(event.getTown()); updateTownMembers(event.getTown());
} }
@EventHandler @EventHandler
public void onNationLeave(NationRemoveTownEvent event) { public void onNationLeave(NationRemoveTownEvent event) {
if (!TownColorComponent.getComponent().useNationColors().get()) return; if (!TownColorComponent.getComponent().useNationColors.get()) return;
updateTownMembers(event.getTown()); //The town still has it's colours updateTownMembers(event.getTown()); //The town still has it's colours
} }
@EventHandler @EventHandler
public void onNationDelete(DeleteNationEvent event) { public void onNationDelete(DeleteNationEvent event) {
if (!TownColorComponent.getComponent().useNationColors().get()) return; if (!TownColorComponent.getComponent().useNationColors.get()) return;
TownColorComponent.NationColor.remove(event.getNationName().toLowerCase()); TownColorComponent.NationColor.remove(event.getNationName().toLowerCase());
} }
@EventHandler @EventHandler
public void onNationCreate(NewNationEvent event) { public void onNationCreate(NewNationEvent event) {
if (!TownColorComponent.getComponent().useNationColors().get()) return; if (!TownColorComponent.getComponent().useNationColors.get()) return;
Player p = Bukkit.getPlayer(event.getNation().getCapital().getMayor().getName()); Player p = Bukkit.getPlayer(event.getNation().getCapital().getMayor().getName());
if (p != null) if (p != null)
p.sendMessage("§6Use /u nationcolor to set a color for the nation."); p.sendMessage("§6Use /u nationcolor to set a color for the nation.");

View file

@ -8,8 +8,10 @@ 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.CustomTabCompleteMethod;
import com.palmergames.bukkit.towny.object.Nation; import com.palmergames.bukkit.towny.object.Nation;
import com.palmergames.bukkit.towny.object.Town; import com.palmergames.bukkit.towny.object.Town;
import com.palmergames.bukkit.towny.object.TownyObject;
import lombok.val; import lombok.val;
import org.bukkit.Bukkit; import org.bukkit.Bukkit;
import org.bukkit.command.CommandSender; import org.bukkit.command.CommandSender;
@ -21,7 +23,7 @@ import org.bukkit.command.CommandSender;
public class NationColorCommand extends AdminCommandBase { public class NationColorCommand extends AdminCommandBase {
@Command2.Subcommand @Command2.Subcommand
public boolean def(CommandSender sender, String nation, String color) { public boolean def(CommandSender sender, String nation, String color) {
final Nation n = TownyComponent.TU.getNationsMap().get(nation.toLowerCase()); final Nation n = TownyComponent.dataSource.getNation(nation);
if (n == null) { if (n == null) {
sender.sendMessage("§cThe nation '" + nation + "' cannot be found."); sender.sendMessage("§cThe nation '" + nation + "' cannot be found.");
return true; return true;
@ -29,6 +31,16 @@ public class NationColorCommand extends AdminCommandBase {
return SetNationColor(sender, n, color); return SetNationColor(sender, n, color);
} }
@CustomTabCompleteMethod(param = "color")
public Iterable<String> def(String nation) {
return TownColorCommand.tabcompleteColor();
}
@CustomTabCompleteMethod(param = "nation")
public Iterable<String> def() {
return TownyComponent.dataSource.getNations().stream().map(TownyObject::getName)::iterator;
}
public static boolean SetNationColor(CommandSender sender, Nation nation, String color) { public static boolean SetNationColor(CommandSender sender, Nation nation, String color) {
val c = TownColorCommand.getColorOrSendError(color, sender); val c = TownColorCommand.getColorOrSendError(color, sender);
if (!c.isPresent()) return true; if (!c.isPresent()) return true;

View file

@ -15,7 +15,7 @@ public class TCCount extends AdminCommandBase {
@Command2.Subcommand @Command2.Subcommand
public boolean def(CommandSender sender, byte count) { public boolean def(CommandSender sender, byte count) {
val comp = TownColorComponent.getComponent(); val comp = TownColorComponent.getComponent();
comp.colorCount().set(count); comp.colorCount.set(count);
sender.sendMessage("Color count set to " + count); sender.sendMessage("Color count set to " + count);
return true; return true;
} }

View file

@ -7,7 +7,9 @@ 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.CustomTabCompleteMethod;
import com.palmergames.bukkit.towny.object.Town; import com.palmergames.bukkit.towny.object.Town;
import com.palmergames.bukkit.towny.object.TownyObject;
import lombok.val; import lombok.val;
import org.bukkit.Bukkit; import org.bukkit.Bukkit;
import org.bukkit.command.CommandSender; import org.bukkit.command.CommandSender;
@ -23,17 +25,31 @@ import java.util.stream.Collectors;
"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.", // "The colors will split the name evenly.", //
}) })
public class TownColorCommand extends AdminCommandBase { //TODO: Command path aliases public class TownColorCommand extends AdminCommandBase {
@Command2.Subcommand @Command2.Subcommand
public boolean def(CommandSender sender, String town, String... colornames) { public boolean def(CommandSender sender, String town, String... colornames) {
if (!TownyComponent.TU.getTownsMap().containsKey(town.toLowerCase())) { if (TownyComponent.dataSource.getTown(town) == null) {
sender.sendMessage("§cThe town '" + town + "' cannot be found.");
return true;
}
Town targetTown = TownyComponent.dataSource.getTown(town);
if (targetTown == null) {
sender.sendMessage("§cThe town '" + town + "' cannot be found."); sender.sendMessage("§cThe town '" + town + "' cannot be found.");
return true; return true;
} }
Town targetTown = TownyComponent.TU.getTownsMap().get(town.toLowerCase());
return SetTownColor(sender, targetTown, colornames); return SetTownColor(sender, targetTown, colornames);
} }
@CustomTabCompleteMethod(param = "colornames")
public Iterable<String> def(String town) {
return TownColorCommand.tabcompleteColor();
}
@CustomTabCompleteMethod(param = "town")
public Iterable<String> def() {
return TownyComponent.dataSource.getTowns().stream().map(TownyObject::getName)::iterator;
}
public static boolean SetTownColor(CommandSender sender, Town town, String[] colors) { public static boolean SetTownColor(CommandSender sender, Town town, String[] colors) {
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++) {
@ -43,7 +59,7 @@ public class TownColorCommand extends AdminCommandBase { //TODO: Command path al
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());
@ -56,7 +72,7 @@ public class TownColorCommand extends AdminCommandBase { //TODO: Command path al
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.dataSource.getTown(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;
} }
@ -100,6 +116,14 @@ 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(); val town = TownyComponent.dataSource.getTown(name);
if (town == null) {
return null;
}
return town.getName();
}
public static Iterable<String> tabcompleteColor() {
return Arrays.stream(Color.values()).skip(1).map(Color::getName)::iterator;
} }
} }

View file

@ -44,7 +44,7 @@ public class TownyAnnouncer {
message, target, ChatUtils.MCORIGIN); message, target, ChatUtils.MCORIGIN);
break; break;
case "Global": case "Global":
TBMCChatAPI.SendSystemMessage(Channel.GlobalChat, TBMCChatAPI.SendSystemMessage(Channel.globalChat,
Channel.RecipientTestResult.ALL, Channel.RecipientTestResult.ALL,
message, target, ChatUtils.MCORIGIN); message, target, ChatUtils.MCORIGIN);
break; break;

View file

@ -1,33 +1,33 @@
package buttondevteam.chat.components.towny; package buttondevteam.chat.components.towny;
import buttondevteam.chat.PluginMain; import buttondevteam.chat.PluginMain;
import buttondevteam.chat.VanillaUtils;
import buttondevteam.chat.components.formatter.formatting.TellrawPart;
import buttondevteam.core.component.channel.Channel; import buttondevteam.core.component.channel.Channel;
import buttondevteam.lib.architecture.Component; import buttondevteam.lib.architecture.Component;
import buttondevteam.lib.chat.Color; import buttondevteam.lib.chat.Color;
import buttondevteam.lib.chat.TBMCChatAPI; import buttondevteam.lib.chat.TBMCChatAPI;
import buttondevteam.lib.player.ChromaGamerBase;
import buttondevteam.lib.player.TBMCPlayerBase;
import com.palmergames.bukkit.towny.TownyAPI;
import com.palmergames.bukkit.towny.TownyUniverse; import com.palmergames.bukkit.towny.TownyUniverse;
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;
import com.palmergames.bukkit.towny.object.Town; import com.palmergames.bukkit.towny.object.Town;
import lombok.val; import lombok.val;
import org.bukkit.command.CommandSender; import net.kyori.adventure.text.TextComponent;
import org.bukkit.entity.Player; import org.bukkit.entity.Player;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.function.Consumer;
import java.util.Optional;
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. * 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. * It provides the TC and NC channels, and posts Towny messages (global, town, nation) to the correct channels for other platforms like Discord.
* You can disable /tc and /nc in Chroma-Core's config if you only want to use the TownColorComponent.
*/ */
public class TownyComponent extends Component<PluginMain> { public class TownyComponent extends Component<PluginMain> {
public static TownyUniverse TU; public static TownyAPI dataSource;
private static ArrayList<String> Towns; private static ArrayList<String> Towns;
private static ArrayList<String> Nations; private static ArrayList<String> Nations;
@ -36,12 +36,12 @@ public class TownyComponent extends Component<PluginMain> {
@Override @Override
protected void enable() { protected void enable() {
TU = TownyUniverse.getInstance(); dataSource = TownyAPI.getInstance();
Towns = TU.getTownsMap().values().stream().map(Town::getName).collect(Collectors.toCollection(ArrayList::new)); // Creates a snapshot of towns, new towns will be added when needed Towns = TownyUniverse.getInstance().getTowns().stream().map(Town::getName).collect(Collectors.toCollection(ArrayList::new)); // Creates a snapshot of towns, new towns will be added when needed
Nations = TU.getNationsMap().values().stream().map(Nation::getName).collect(Collectors.toCollection(ArrayList::new)); // Same here but with nations Nations = TownyUniverse.getInstance().getNations().stream().map(Nation::getName).collect(Collectors.toCollection(ArrayList::new)); // Same here but with nations
TBMCChatAPI.RegisterChatChannel( TBMCChatAPI.registerChatChannel(
TownChat = new Channel("§3TC§f", Color.DarkAqua, "tc", s -> checkTownNationChat(s, false))); TownChat = new Channel("§3TC§f", Color.DarkAqua, "tc", s -> checkTownNationChat(s, false)));
TBMCChatAPI.RegisterChatChannel( TBMCChatAPI.registerChatChannel(
NationChat = new Channel("§6NC§f", Color.Gold, "nc", s -> checkTownNationChat(s, true))); NationChat = new Channel("§6NC§f", Color.Gold, "nc", s -> checkTownNationChat(s, true)));
TownyAnnouncer.setup(TownChat, NationChat); TownyAnnouncer.setup(TownChat, NationChat);
} }
@ -51,30 +51,34 @@ public class TownyComponent extends Component<PluginMain> {
TownyAnnouncer.setdown(); TownyAnnouncer.setdown();
} }
public void handleSpiesInit(Channel channel, TellrawPart json, Function<TellrawPart, String> toJson) { public Consumer<Player> handleSpiesInit(Channel channel, TextComponent.Builder json) {
if (channel.ID.equals(TownChat.ID) || channel.ID.equals(NationChat.ID)) { if (channel.getIdentifier().equals(TownChat.getIdentifier()) || channel.getIdentifier().equals(NationChat.getIdentifier())) {
((List<TellrawPart>) json.getExtra()).add(0, new TellrawPart("[SPY]")); // TODO: Cannot prepend to json, so we need to run this ealier
jsonstr = toJson.apply(json); //((List<TellrawPart>) json.getExtra()).add(0, new TellrawPart("[SPY]"));
return p -> handleSpies(channel, p, json);
} }
return p -> {};
} }
private String jsonstr; private void handleSpies(Channel channel, Player p, TextComponent.Builder jsonstr) {
if (channel.getIdentifier().equals(TownChat.getIdentifier()) || channel.getIdentifier().equals(NationChat.getIdentifier())) {
public void handleSpies(Channel channel, Player p) { val res = dataSource.getResident(p.getName());
if (channel.ID.equals(TownChat.ID) || channel.ID.equals(NationChat.ID)) { if (res == null) {
if (Optional.ofNullable(TU.getResidentMap().get(p.getName().toLowerCase())) return;
.filter(r -> r.hasMode("spy")).isPresent()) }
VanillaUtils.tellRaw(p, jsonstr); if (res.hasMode("spy"))
p.sendMessage(jsonstr.build());
} }
} }
/** /**
* Return the error message for the message sender if they can't send it and the score * Return the error message for the message sender if they can't send it and the score
*/ */
private static Channel.RecipientTestResult checkTownNationChat(CommandSender sender, boolean nationchat) { private static Channel.RecipientTestResult checkTownNationChat(ChromaGamerBase user, boolean nationchat) {
if (!(sender instanceof Player)) if (!(user instanceof TBMCPlayerBase))
return new Channel.RecipientTestResult("§cYou are not a player!"); return new Channel.RecipientTestResult("§cYou are not a player!");
Resident resident = TU.getResidentMap().get(sender.getName().toLowerCase()); val sender = ((TBMCPlayerBase) user).getOfflinePlayer();
Resident resident = dataSource.getResident(sender.getName());
Channel.RecipientTestResult result = checkTownNationChatInternal(nationchat, resident); Channel.RecipientTestResult result = checkTownNationChatInternal(nationchat, resident);
if (result.errormessage != null && resident != null && resident.getModes().contains("spy")) // Only use spy if they wouldn't see it if (result.errormessage != null && resident != null && resident.getModes().contains("spy")) // Only use spy if they wouldn't see it
result = new Channel.RecipientTestResult(1000, "allspies"); // There won't be more than a thousand towns/nations probably result = new Channel.RecipientTestResult(1000, "allspies"); // There won't be more than a thousand towns/nations probably

View file

@ -7,31 +7,27 @@ import buttondevteam.chat.commands.ucmds.HistoryCommand;
import buttondevteam.chat.components.flair.FlairComponent; import buttondevteam.chat.components.flair.FlairComponent;
import buttondevteam.chat.components.flair.FlairStates; import buttondevteam.chat.components.flair.FlairStates;
import buttondevteam.core.ComponentManager; import buttondevteam.core.ComponentManager;
import buttondevteam.lib.player.TBMCPlayerJoinEvent; import buttondevteam.lib.player.ChromaGamerBase;
import buttondevteam.lib.player.TBMCPlayerLoadEvent; import buttondevteam.lib.player.TBMCPlayerBase;
import buttondevteam.lib.player.TBMCPlayerSaveEvent;
import org.bukkit.entity.Player; import org.bukkit.entity.Player;
import org.bukkit.event.EventHandler; import org.bukkit.event.EventHandler;
import org.bukkit.event.EventPriority;
import org.bukkit.event.Listener; import org.bukkit.event.Listener;
import org.bukkit.event.player.PlayerJoinEvent;
import org.bukkit.event.player.PlayerQuitEvent; import org.bukkit.event.player.PlayerQuitEvent;
import java.util.Timer; import java.util.Timer;
public class PlayerJoinLeaveListener implements Listener { public class PlayerJoinLeaveListener implements Listener {
@EventHandler @EventHandler(priority = EventPriority.HIGHEST)
public void onPlayerLoad(TBMCPlayerLoadEvent e) { public void onPlayerJoin(PlayerJoinEvent e) {
ChatPlayer cp = e.GetPlayer().asPluginPlayer(ChatPlayer.class);
cp.FlairUpdate();
}
@EventHandler
public void onPlayerTBMCJoin(TBMCPlayerJoinEvent e) {
ChatPlayer cp = e.GetPlayer().asPluginPlayer(ChatPlayer.class);
Player p = e.getPlayer(); Player p = e.getPlayer();
ChatPlayer cp = TBMCPlayerBase.getPlayer(p.getUniqueId(), ChatPlayer.class);
cp.FlairUpdate();
if (ComponentManager.isEnabled(FlairComponent.class)) { if (ComponentManager.isEnabled(FlairComponent.class)) {
if (!cp.FlairState().get().equals(FlairStates.NoComment)) { if (!cp.FlairState.get().equals(FlairStates.NoComment)) {
FlairComponent.ConfirmUserMessage(cp); FlairComponent.ConfirmUserMessage(cp);
Timer timer = new Timer(); Timer timer = new Timer();
PlayerJoinTimerTask tt = new PlayerJoinTimerTask() { PlayerJoinTimerTask tt = new PlayerJoinTimerTask() {
@ -55,14 +51,10 @@ public class PlayerJoinLeaveListener implements Listener {
nwithoutformatting = nwithoutformatting.replace("§" + nwithoutformatting.charAt(index + 1), ""); nwithoutformatting = nwithoutformatting.replace("§" + nwithoutformatting.charAt(index + 1), "");
} else } else
nwithoutformatting = p.getName(); nwithoutformatting = p.getName();
PlayerListener.nicknames.forcePut(nwithoutformatting.toLowerCase(), p.getUniqueId()); //TODO: FormatterComponent PlayerListener.nicknames.forcePut(nwithoutformatting.toLowerCase(), p.getUniqueId());
if (PluginMain.Instance.storeChatHistory().get()) if (PluginMain.Instance.storeChatHistory.get())
HistoryCommand.showHistory(e.getPlayer(), null); HistoryCommand.showHistory(ChromaGamerBase.getFromSender(e.getPlayer()), null);
}
@EventHandler
public void onPlayerSave(TBMCPlayerSaveEvent e) {
} }
@EventHandler @EventHandler

View file

@ -8,44 +8,31 @@ import buttondevteam.chat.components.flair.FlairComponent;
import buttondevteam.chat.components.formatter.FormatterComponent; import buttondevteam.chat.components.formatter.FormatterComponent;
import buttondevteam.chat.components.towncolors.TownColorComponent; import buttondevteam.chat.components.towncolors.TownColorComponent;
import buttondevteam.core.ComponentManager; import buttondevteam.core.ComponentManager;
import buttondevteam.core.component.channel.Channel;
import buttondevteam.core.component.channel.ChatRoom;
import buttondevteam.lib.ChromaUtils;
import buttondevteam.lib.TBMCChatEvent; import buttondevteam.lib.TBMCChatEvent;
import buttondevteam.lib.TBMCCoreAPI; import buttondevteam.lib.TBMCCoreAPI;
import buttondevteam.lib.TBMCSystemChatEvent;
import buttondevteam.lib.chat.ChatMessage;
import buttondevteam.lib.chat.TBMCChatAPI;
import buttondevteam.lib.player.ChromaGamerBase; import buttondevteam.lib.player.ChromaGamerBase;
import buttondevteam.lib.player.ChromaGamerBase.InfoTarget; import buttondevteam.lib.player.ChromaGamerBase.InfoTarget;
import buttondevteam.lib.player.TBMCPlayerGetInfoEvent; import buttondevteam.lib.player.TBMCPlayerGetInfoEvent;
import com.google.common.collect.BiMap; import com.google.common.collect.BiMap;
import com.google.common.collect.HashBiMap; import com.google.common.collect.HashBiMap;
import lombok.val;
import net.ess3.api.events.NickChangeEvent; import net.ess3.api.events.NickChangeEvent;
import org.bukkit.Bukkit; import org.bukkit.Bukkit;
import org.bukkit.ChatColor; import org.bukkit.ChatColor;
import org.bukkit.command.CommandSender;
import org.bukkit.command.ConsoleCommandSender;
import org.bukkit.entity.Player; import org.bukkit.entity.Player;
import org.bukkit.event.EventHandler; import org.bukkit.event.EventHandler;
import org.bukkit.event.EventPriority; import org.bukkit.event.EventPriority;
import org.bukkit.event.Listener; import org.bukkit.event.Listener;
import org.bukkit.event.player.AsyncPlayerChatEvent; import org.bukkit.event.player.AsyncPlayerChatEvent;
import org.bukkit.event.player.PlayerChatTabCompleteEvent; import org.bukkit.event.player.PlayerChatTabCompleteEvent;
import org.bukkit.event.player.PlayerCommandPreprocessEvent;
import org.bukkit.event.server.ServerCommandEvent;
import java.util.Arrays;
import java.util.Map.Entry; import java.util.Map.Entry;
import java.util.UUID; import java.util.UUID;
import java.util.function.BiPredicate;
public class PlayerListener implements Listener { public class PlayerListener implements Listener {
/** /**
* Does not contain format codes, lowercased * Does not contain format codes, lowercased
*/ */
public static BiMap<String, UUID> nicknames = HashBiMap.create(); public static final BiMap<String, UUID> nicknames = HashBiMap.create();
@EventHandler(priority = EventPriority.HIGHEST) @EventHandler(priority = EventPriority.HIGHEST)
public void onPlayerChat(AsyncPlayerChatEvent event) { public void onPlayerChat(AsyncPlayerChatEvent event) {
@ -56,77 +43,6 @@ public class PlayerListener implements Listener {
event.setCancelled(true); // The custom event should only be cancelled when muted or similar event.setCancelled(true); // The custom event should only be cancelled when muted or similar
} }
@EventHandler(priority = EventPriority.HIGHEST)
public void PlayerCommandPreprocess(PlayerCommandPreprocessEvent event) {
if (!event.isCancelled())
event.setCancelled(onCommandPreprocess(event.getPlayer(), event.getMessage()));
}
private boolean onCommandPreprocess(CommandSender sender, String message) {
if (message.length() < 2)
return false;
int index = message.indexOf(" ");
val mp = ChromaGamerBase.getFromSender(sender);
String cmd;
final BiPredicate<Channel, String> checkchid = (chan, cmd1) -> cmd1.equalsIgnoreCase(chan.ID) || (Arrays.stream(chan.IDs().get()).anyMatch(cmd1::equalsIgnoreCase));
if (index == -1) { // Only the command is run
if (!(sender instanceof Player || sender instanceof ConsoleCommandSender))
return false;
// ^^ We can only store player or console channels - Directly sending to channels would still work if they had an event
cmd = sender instanceof ConsoleCommandSender ? message : message.substring(1);
for (Channel channel : ((Iterable<Channel>) Channel.getChannels()::iterator)) { //Using Stream.forEach would be too easy
if (checkchid.test(channel, cmd)) {
Channel oldch = mp.channel().get();
if (oldch instanceof ChatRoom)
((ChatRoom) oldch).leaveRoom(sender);
if (oldch.equals(channel))
mp.channel().set(Channel.GlobalChat);
else {
mp.channel().set(channel);
if (channel instanceof ChatRoom)
((ChatRoom) channel).joinRoom(sender);
}
sender.sendMessage("§6You are now talking in: §b" + mp.channel().get().DisplayName().get());
return true;
}
}
} else { // We have arguments
cmd = sender instanceof ConsoleCommandSender ? message.substring(0, index) : message.substring(1, index);
if (cmd.equalsIgnoreCase("tpahere")) {
Player player = Bukkit.getPlayer(message.substring(index + 1));
if (player != null && sender instanceof Player)
player.sendMessage("§b" + ((Player) sender).getDisplayName() + " §bis in this world: " //TODO: Move to the Core
+ ((Player) sender).getWorld().getName());
} else if (cmd.equalsIgnoreCase("minecraft:me")) {
if (!(sender instanceof Player) || !PluginMain.essentials.getUser((Player) sender).isMuted()) {
String msg = message.substring(index + 1);
TBMCChatAPI.SendSystemMessage(Channel.GlobalChat, Channel.RecipientTestResult.ALL, String.format("* %s %s", ChromaUtils.getDisplayName(sender), msg), TBMCSystemChatEvent.BroadcastTarget.ALL); //TODO: Don't send to all
return true;
} else {
sender.sendMessage("§cCan't use /minecraft:me while muted.");
return true;
}
} else if (cmd.equalsIgnoreCase("me")) { //Take over for Discord broadcast
if (!(sender instanceof Player) || !PluginMain.essentials.getUser((Player) sender).isMuted()) {
String msg = message.substring(index + 1);
Bukkit.broadcastMessage(String.format("§5* %s %s", sender instanceof Player ? ((Player) sender).getDisplayName() : sender.getName(), msg));
return true;
} else {
sender.sendMessage("§cCan't use /me while muted.");
return true;
}
} else
for (Channel channel : (Iterable<Channel>) Channel.getChannels()::iterator) {
if (checkchid.test(channel, cmd)) { //Apparently method references don't require final variables
TBMCChatAPI.SendChatMessage(ChatMessage.builder(sender, mp, message.substring(index + 1)).build(), channel);
return true;
}
}
// TODO: Target selectors
}
return false;
}
@EventHandler @EventHandler
public void onTabComplete(PlayerChatTabCompleteEvent e) { public void onTabComplete(PlayerChatTabCompleteEvent e) {
String name = e.getLastToken(); String name = e.getLastToken();
@ -136,29 +52,20 @@ public class PlayerListener implements Listener {
} }
} }
@EventHandler(priority = EventPriority.HIGHEST)
public void onConsoleCommand(ServerCommandEvent event) {
if (onCommandPreprocess(event.getSender(), event.getCommand()))
event.setCommand("dontrunthiscmd");
}
@EventHandler @EventHandler
public void onGetInfo(TBMCPlayerGetInfoEvent e) { public void onGetInfo(TBMCPlayerGetInfoEvent e) {
try (ChatPlayer cp = e.getPlayer().getAs(ChatPlayer.class)) { ChatPlayer cp = e.getPlayer().getAs(ChatPlayer.class);
if (cp == null) if (cp == null)
return; return;
e.addInfo("Minecraft name: " + cp.PlayerName().get()); e.addInfo("Minecraft name: " + cp.getPlayerName());
if (cp.UserName().get() != null && cp.UserName().get().length() > 0) if (cp.UserName.get() != null && cp.UserName.get().length() > 0)
e.addInfo("Reddit name: " + cp.UserName().get()); e.addInfo("Reddit name: " + cp.UserName.get());
if (ComponentManager.isEnabled(FlairComponent.class)) { if (ComponentManager.isEnabled(FlairComponent.class)) {
final String flair = cp.GetFormattedFlair(e.getTarget() != InfoTarget.MCCommand); final String flair = cp.GetFormattedFlair(e.getTarget() != InfoTarget.MCCommand);
if (flair.length() > 0) if (flair.length() > 0)
e.addInfo("/r/TheButton flair: " + flair); e.addInfo("/r/TheButton flair: " + flair);
}
e.addInfo(String.format("Respect: %.2f", cp.getF()));
} catch (Exception ex) {
TBMCCoreAPI.SendException("Error while providing chat info for player " + e.getPlayer().getFileName(), ex);
} }
e.addInfo(String.format("Respect: %.2f", cp.getF()));
} }
private long lastError = 0; private long lastError = 0;
@ -168,18 +75,18 @@ public class PlayerListener implements Listener {
try { try {
if (e.isCancelled()) if (e.isCancelled())
return; return;
HistoryCommand.addChatMessage(e.getCm(), e.getChannel()); HistoryCommand.addChatMessage(e.getChatMessage(), 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 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 && 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 lastError = System.nanoTime(); //I put the whole thing in the if to protect against race conditions
for (Player p : Bukkit.getOnlinePlayers()) for (Player p : Bukkit.getOnlinePlayers())
if (e.shouldSendTo(p)) if (e.shouldSendTo(ChromaGamerBase.getFromSender(p)))
p.sendMessage("[" + e.getChannel().DisplayName().get() + "] §cSome features in the message below might be unavailable due to an error."); 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);
TBMCCoreAPI.SendException("An error occured while processing a chat message!", ex); TBMCCoreAPI.SendException("An error occured while processing a chat message!", ex, PluginMain.Instance);
} }
} }
@ -187,9 +94,9 @@ public class PlayerListener implements Listener {
public void onNickChange(NickChangeEvent e) { public void onNickChange(NickChangeEvent e) {
String nick = e.getValue(); String nick = e.getValue();
if (nick == null) if (nick == null)
nicknames.inverse().remove(e.getAffected().getBase().getUniqueId()); nicknames.inverse().remove(e.getController().getBase().getUniqueId()); //EssentialsX has it swapped
else else
nicknames.inverse().forcePut(e.getAffected().getBase().getUniqueId(), ChatColor.stripColor(nick).toLowerCase()); nicknames.inverse().forcePut(e.getController().getBase().getUniqueId(), ChatColor.stripColor(nick).toLowerCase());
Bukkit.getScheduler().runTaskLater(PluginMain.Instance, () -> { Bukkit.getScheduler().runTaskLater(PluginMain.Instance, () -> {
TownColorComponent.updatePlayerColors(e.getAffected().getBase()); //Won't fire this event again TownColorComponent.updatePlayerColors(e.getAffected().getBase()); //Won't fire this event again

View file

@ -4,7 +4,7 @@ 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.bukkit.plugin.Plugin;
import org.dynmap.bukkit.DynmapPlugin; import org.dynmap.DynmapCommonAPI;
import org.dynmap.markers.MarkerAPI; import org.dynmap.markers.MarkerAPI;
import java.lang.reflect.Constructor; import java.lang.reflect.Constructor;
@ -35,7 +35,7 @@ public class DTBridge {
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()); ((DynmapCommonAPI) Bukkit.getPluginManager().getPlugin("dynmap")).getMarkerAPI());
map.put(townname, style); map.put(townname, style);
} }
set(cl, style, "fillcolor", fillcolor); set(cl, style, "fillcolor", fillcolor);

View file

@ -1,18 +1,14 @@
name: Chroma-Chat name: Chroma-Chat
main: buttondevteam.chat.PluginMain main: buttondevteam.chat.PluginMain
version: '4.0' version: '${noprefix.version}'
commands: commands:
u: u:
description: Auto-flair system. Accept or ignore flair. description: The main command for Chroma-Chat.
ooc:
description: Send message Out-of-Character.
alias: nrp
unlol: unlol:
description: Unlaugh the last laugh. description: Unlaugh the last laugh.
alias: unlaugh alias: unlaugh
mwiki: mwiki:
description: Search the wiki. description: Search the wiki.
dontrunthiscmd: null
tableflip: tableflip:
description: Flip a table. description: Flip a table.
unflip: unflip:
@ -30,19 +26,22 @@ commands:
description: Lenny face. description: Lenny face.
ftop: ftop:
description: Top respect. description: Top respect.
me:
description: Me command with Chroma support.
author: NorbiPeti author: NorbiPeti
depend: depend:
- Essentials - Essentials
- Vault - Vault
- ChromaCore - Chroma-Core
soft-depend: softdepend:
- Minigames - Dynmap-Towny
- Dynmap-Towny - Towny
- Towny - dynmap
permissions: permissions:
tbmc.badge.gold: tbmc.badge.gold:
description: Gives a patron badge. description: Gives a patron badge.
default: false default: false
tbmc.badge.diamond: tbmc.badge.diamond:
description: Gives a cool patron badge. description: Gives a cool patron badge.
default: false default: false
api-version: '1.13'

View file

@ -1,103 +1,129 @@
package buttondevteam.chat.components.formatter; package buttondevteam.chat.components.formatter;
import buttondevteam.chat.ChatPlayer;
import buttondevteam.chat.ChatUtils; import buttondevteam.chat.ChatUtils;
import buttondevteam.chat.ObjectTestRunner; import buttondevteam.chat.ObjectTestRunner;
import buttondevteam.chat.ObjectTestRunner.Objects; import buttondevteam.chat.ObjectTestRunner.Objects;
import buttondevteam.chat.PluginMain; import buttondevteam.chat.PluginMain;
import buttondevteam.chat.commands.ucmds.admin.DebugCommand; import buttondevteam.chat.commands.ucmds.admin.DebugCommand;
import buttondevteam.chat.components.formatter.formatting.*; import buttondevteam.chat.components.formatter.formatting.ChatFormatter;
import buttondevteam.chat.components.formatter.formatting.TellrawEvent.ClickAction; import buttondevteam.chat.components.formatter.formatting.FormatSettings;
import buttondevteam.chat.components.formatter.formatting.TellrawEvent.HoverAction; import buttondevteam.chat.components.formatter.formatting.MatchProviderBase;
import buttondevteam.core.TestPrepare; import buttondevteam.core.MainPlugin;
import buttondevteam.core.component.channel.Channel; import buttondevteam.core.component.channel.Channel;
import buttondevteam.lib.chat.Color; import buttondevteam.lib.player.ChromaGamerBase;
import net.milkbowl.vault.permission.Permission; import buttondevteam.lib.test.TestPermissions;
import org.bukkit.command.CommandSender; import net.kyori.adventure.text.Component;
import net.kyori.adventure.text.TextComponent;
import org.junit.Assert; import org.junit.Assert;
import org.junit.Test; import org.junit.Test;
import org.junit.runner.RunWith; import org.junit.runner.RunWith;
import org.mockito.Mockito;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import java.util.UUID;
import java.util.function.Function;
import static be.seeseemelk.mockbukkit.MockBukkit.load;
import static be.seeseemelk.mockbukkit.MockBukkit.mock;
import static net.kyori.adventure.text.Component.text;
import static net.kyori.adventure.text.event.ClickEvent.Action.OPEN_URL;
import static net.kyori.adventure.text.event.ClickEvent.clickEvent;
import static net.kyori.adventure.text.event.HoverEvent.Action.SHOW_TEXT;
import static net.kyori.adventure.text.event.HoverEvent.hoverEvent;
import static net.kyori.adventure.text.format.NamedTextColor.*;
import static net.kyori.adventure.text.format.TextDecoration.*;
@RunWith(ObjectTestRunner.class) @RunWith(ObjectTestRunner.class)
public class ChatFormatIT { public class ChatFormatIT {
@Objects @Objects
public static List<Object> data() { public static List<Object> data() {
TestPrepare.PrepareServer(); mock();
final CommandSender sender = Mockito.mock(CommandSender.class); load(MainPlugin.class, true);
var sender = ChromaGamerBase.getUser(UUID.randomUUID().toString(), ChatPlayer.class);
DebugCommand.DebugMode = true; DebugCommand.DebugMode = true;
PluginMain.permission = Mockito.mock(Permission.class); PluginMain.permission = new TestPermissions();
List<Object> list = new ArrayList<>(); List<Object> list = new ArrayList<>();
list.add(new ChatFormatIT(sender, "*test*", new TellrawPart("test").setItalic(true).setColor(Color.White))); list.add(new ChatFormatIT(sender, "*test*", text("test").decorate(ITALIC).color(WHITE)));
list.add(new ChatFormatIT(sender, "**test**", new TellrawPart("test").setBold(true).setColor(Color.White))); list.add(new ChatFormatIT(sender, "**test**", text("test").decorate(BOLD).color(WHITE)));
list.add(new ChatFormatIT(sender, "***test***", list.add(new ChatFormatIT(sender, "***test***", text("test").decorate(BOLD, ITALIC).color(WHITE)));
new TellrawPart("test").setBold(true).setItalic(true).setColor(Color.White))); list.add(new ChatFormatIT(sender, "***__test__***", text("test").decorate(BOLD, ITALIC, UNDERLINED).color(WHITE)));
list.add(new ChatFormatIT(sender, "***__test__***", list.add(new ChatFormatIT(sender, "***__~~test~~__***", text("test").decorate(BOLD, ITALIC, UNDERLINED, STRIKETHROUGH).color(WHITE)));
new TellrawPart("test").setBold(true).setItalic(true).setUnderlined(true).setColor(Color.White))); list.add(new ChatFormatIT(sender, "¯\\\\\\_(ツ)\\_/¯", text("¯\\_(ツ)_/¯").color(WHITE)));
list.add(new ChatFormatIT(sender, "***__~~test~~__***", new TellrawPart("test").setBold(true).setItalic(true)
.setUnderlined(true).setStrikethrough(true).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) text("https://google.hu/").color(WHITE).decorate(UNDERLINED)
.setHoverEvent(TellrawEvent.create(HoverAction.SHOW_TEXT, .hoverEvent(hoverEvent(SHOW_TEXT, text("Click to open").color(BLUE)))
new TellrawPart("Click to open").setColor(Color.Blue))) .clickEvent(clickEvent(OPEN_URL, "https://google.hu/"))));
.setClickEvent(TellrawEvent.create(ClickAction.OPEN_URL, "https://google.hu/")))); list.add(new ChatFormatIT(sender, "*test", text("*test").color(WHITE)));
list.add(new ChatFormatIT(sender, "*test", new TellrawPart("*test").setColor(Color.White))); list.add(new ChatFormatIT(sender, "**test*", text("**test*").color(WHITE)));
list.add(new ChatFormatIT(sender, "**test*", new TellrawPart("**test*").setColor(Color.White))); list.add(new ChatFormatIT(sender, "***test", text("***test").color(WHITE)));
list.add(new ChatFormatIT(sender, "***test", new TellrawPart("***test").setColor(Color.White))); list.add(new ChatFormatIT(sender, "Koiiev", text("§bKoiiev§r").color(AQUA)));
list.add(new ChatFormatIT(sender, "Koiiev", new TellrawPart("§bKoiiev§r").setColor(Color.Aqua))); list.add(new ChatFormatIT(sender, "norbipeti", text("§bNorbiPeti§r").color(AQUA)));
list.add(new ChatFormatIT(sender, "norbipeti", new TellrawPart("§bNorbiPeti§r").setColor(Color.Aqua))); list.add(new ChatFormatIT(sender, "Arsen_Derby_FTW", text("§bArsen_Derby_FTW§r").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", text("§bcarrot_lynx§r").color(AQUA)));
list.add(new ChatFormatIT(sender, "carrot_lynx", new TellrawPart("§bcarrot_lynx§r").setColor(Color.Aqua))); list.add(new ChatFormatIT(sender, "*carrot_lynx*", text("§bcarrot_lynx§r").decorate(ITALIC).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/", text("https://norbipeti.github.io/")
list.add(new ChatFormatIT(sender, "https://norbipeti.github.io/", new TellrawPart("https://norbipeti.github.io/") .color(WHITE).decorate(UNDERLINED)
.setColor(Color.White).setUnderlined(true) .hoverEvent(hoverEvent(SHOW_TEXT, text("Click to open").color(BLUE)))
.setHoverEvent(TellrawEvent.create(HoverAction.SHOW_TEXT, .clickEvent(clickEvent(OPEN_URL, "https://norbipeti.github.io/"))));
new TellrawPart("Click to open").setColor(Color.Blue))) list.add(new ChatFormatIT(sender, "*https://norbipeti.github.io/ heh*", text("https://norbipeti.github.io/").decorate(ITALIC).decorate(UNDERLINED)
.setClickEvent(TellrawEvent.create(ClickAction.OPEN_URL, "https://norbipeti.github.io/")))); .hoverEvent(hoverEvent(SHOW_TEXT, text("Click to open").color(BLUE)))
list.add(new ChatFormatIT(sender, "*https://norbipeti.github.io/ heh*", new TellrawPart("https://norbipeti.github.io/").setItalic(true).setUnderlined(true) .clickEvent(clickEvent(OPEN_URL, "https://norbipeti.github.io/")).color(WHITE), text(" heh").decorate(ITALIC).color(WHITE)));
.setHoverEvent(TellrawEvent.create(HoverAction.SHOW_TEXT, list.add(new ChatFormatIT(sender, "*test _test_ test*", text("test test test").decorate(ITALIC).color(WHITE)));
new TellrawPart("Click to open").setColor(Color.Blue))) list.add(new ChatFormatIT(sender, "*test __test__ test*", text("test ").decorate(ITALIC).color(WHITE),
.setClickEvent(TellrawEvent.create(ClickAction.OPEN_URL, "https://norbipeti.github.io/")).setColor(Color.White), new TellrawPart(" heh").setItalic(true).setColor(Color.White))); text("test").decorate(ITALIC).decorate(UNDERLINED).color(WHITE), text(" test").decorate(ITALIC).color(WHITE)));
list.add(new ChatFormatIT(sender, "*test _test_ test*", new TellrawPart("test test test").setItalic(true).setColor(Color.White))); list.add(new ChatFormatIT(sender, "**test __test__ test**", text("test ").decorate(BOLD).color(WHITE),
list.add(new ChatFormatIT(sender, "*test __test__ test*", new TellrawPart("test ").setItalic(true).setColor(Color.White), text("test").decorate(BOLD).decorate(UNDERLINED).color(WHITE), text(" test").decorate(BOLD).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**", text("test ").decorate(BOLD).color(WHITE),
list.add(new ChatFormatIT(sender, "**test __test__ test**", new TellrawPart("test ").setBold(true).setColor(Color.White), text("test").decorate(ITALIC).decorate(BOLD).color(WHITE), text(" test").decorate(BOLD).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, "https://norbipeti.github.io/test?test&test#test", text("https://norbipeti.github.io/test?test&test#test")
list.add(new ChatFormatIT(sender, "**test _test_ test**", new TellrawPart("test ").setBold(true).setColor(Color.White), .color(WHITE).decorate(UNDERLINED)
new TellrawPart("test").setItalic(true).setBold(true).setColor(Color.White), new TellrawPart(" test").setBold(true).setColor(Color.White))); .hoverEvent(hoverEvent(SHOW_TEXT, text("Click to open").color(BLUE)))
list.add(new ChatFormatIT(sender, "https://norbipeti.github.io/test?test&test#test", new TellrawPart("https://norbipeti.github.io/test?test&test#test") .clickEvent(clickEvent(OPEN_URL, "https://norbipeti.github.io/test?test&test#test"))));
.setColor(Color.White).setUnderlined(true) list.add(new ChatFormatIT(sender, "[hmm](https://norbipeti.github.io/test)", text("hmm")
.setHoverEvent(TellrawEvent.create(HoverAction.SHOW_TEXT, .color(WHITE).decorate(UNDERLINED)
new TellrawPart("Click to open").setColor(Color.Blue))) .hoverEvent(hoverEvent(SHOW_TEXT, text("Click to open").color(BLUE)))
.setClickEvent(TellrawEvent.create(ClickAction.OPEN_URL, "https://norbipeti.github.io/test?test&test#test")))); .clickEvent(clickEvent(OPEN_URL, "https://norbipeti.github.io/test"))));
list.add(new ChatFormatIT(sender, "[hmm](https://norbipeti.github.io/test)", new TellrawPart("hmm") var space = text(" ").color(WHITE);
.setColor(Color.White).setUnderlined(true) list.add(new ChatFormatIT(sender, "A rainbow text for testing. O", text("A").color(RED),
.setHoverEvent(TellrawEvent.create(HoverAction.SHOW_TEXT, space, text("rainbow").color(GOLD), space, text("text").color(YELLOW),
new TellrawPart("Click to open").setColor(Color.Blue))) space, text("for").color(GREEN), space, text("testing.").color(BLUE),
.setClickEvent(TellrawEvent.create(ClickAction.OPEN_URL, "https://norbipeti.github.io/test")))); space, text("O").color(DARK_PURPLE)).setRainbowMode());
TellrawPart space = new TellrawPart(" ").setColor(Color.White); list.add(new ChatFormatIT(sender, "***test*** test", text("test").color(WHITE)
list.add(new ChatFormatIT(sender, "A rainbow text for testing. O", new TellrawPart("A").setColor(Color.Red), .decorate(ITALIC).decorate(BOLD), text(" test").color(WHITE)));
space, new TellrawPart("rainbow").setColor(Color.Gold), space, new TellrawPart("text").setColor(Color.Yellow), list.add(new ChatFormatIT(sender, ">test message\nheh", text(">test message\nheh").color(GREEN)));
space, new TellrawPart("for").setColor(Color.Green), space, new TellrawPart("testing.").setColor(Color.Blue), list.add(new ChatFormatIT(sender, "[here's a link]()", text("[here's a link]()").color(WHITE)));
space, new TellrawPart("O").setColor(Color.DarkPurple)).setRainbowMode()); list.add(new ChatFormatIT(sender, "[](fakelink)", text("[](fakelink)").color(WHITE)));
list.add(new ChatFormatIT(sender, "||this is a spoiler||", text("this is a spoiler").color(WHITE)
.decorate(OBFUSCATED).hoverEvent(hoverEvent(SHOW_TEXT, text("this is a spoiler")))));
Function<String, TextComponent> whiteBoldItalic = text -> text(text).color(WHITE).decorate(BOLD).decorate(ITALIC);
list.add(new ChatFormatIT(sender, "***some complicated ||test message|| with [links](https://chromagaming.figytuna.com) and other __greatness__ by NorbiPeti***",
whiteBoldItalic.apply("some complicated "),
whiteBoldItalic.apply("test message").decorate(OBFUSCATED).hoverEvent(hoverEvent(SHOW_TEXT, text("test message"))),
whiteBoldItalic.apply(" with "),
whiteBoldItalic.apply("links").clickEvent(clickEvent(OPEN_URL, "https://chromagaming.figytuna.com"))
.decorate(UNDERLINED).hoverEvent(hoverEvent(SHOW_TEXT, text("Click to open").color(BLUE))),
whiteBoldItalic.apply(" and other "),
whiteBoldItalic.apply("greatness").decorate(UNDERLINED),
whiteBoldItalic.apply(" by "),
whiteBoldItalic.apply("§bNorbiPeti§r").color(AQUA))); //§b: flair color
list.add(new ChatFormatIT(sender, "hey @console", text("hey ").color(WHITE),
text("@console").color(AQUA)));
return list; return list;
} }
private final CommandSender sender; private final ChromaGamerBase sender;
private final String message; private final String message;
private final TellrawPart[] extras; private final Component[] extras;
private boolean rainbowMode; private boolean rainbowMode;
public ChatFormatIT(CommandSender sender, String message, TellrawPart... expectedextras) { public ChatFormatIT(ChromaGamerBase sender, String message, Component... expectedExtras) {
this.sender = sender; this.sender = sender;
this.message = message; this.message = message;
this.extras = expectedextras; this.extras = expectedExtras;
} }
private ChatFormatIT setRainbowMode() { private ChatFormatIT setRainbowMode() {
@ -107,18 +133,16 @@ public class ChatFormatIT {
@Test @Test
public void testMessage() { public void testMessage() {
ArrayList<MatchProviderBase> cfs = ChatProcessing.addFormatters(p -> true, null);
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);
ChatFormatter.Combine(cfs, message, tp, null, FormatSettings.builder().color(Color.White).build());
System.out.println("Testing: " + message); System.out.println("Testing: " + message);
// System.out.println(ChatProcessing.toJson(tp)); ArrayList<MatchProviderBase> cfs = ChatProcessing.addFormatters(p -> true, null);
final TellrawPart expectedtp = ChatProcessing.createTellraw(sender, message, null, null, null, chid, ChatUtils.MCORIGIN); final String chid = ChatProcessing.getChannelID(Channel.globalChat, ChatUtils.MCORIGIN);
// System.out.println("Raw: " + ChatProcessing.toJson(expectedtp)); if (rainbowMode)
for (TellrawPart extra : extras) ChatProcessing.createRPC(WHITE, cfs);
expectedtp.addExtra(extra); final TextComponent.Builder tp = ChatProcessing.createEmptyMessageLine(sender, message, null, chid, ChatUtils.MCORIGIN);
Assert.assertEquals(ChatProcessing.toJson(expectedtp), ChatProcessing.toJson(tp)); ChatFormatter.Combine(cfs, message, tp, null, FormatSettings.builder().color(WHITE).build());
final TextComponent.Builder expectedtp = ChatProcessing.createEmptyMessageLine(sender, message, null, chid, ChatUtils.MCORIGIN);
for (Component extra : extras)
expectedtp.append(extra);
Assert.assertEquals(expectedtp.build(), tp.build());
} }
} }