Compare commits
145 commits
Author | SHA1 | Date | |
---|---|---|---|
9eb2354b3f | |||
5615bbcb22 | |||
cde0d44b04 | |||
0d59dff86e | |||
222d393420 | |||
02e05e360e | |||
6bd1de6217 | |||
5d0bd37b28 | |||
f909eb4779 | |||
8d63394b55 | |||
ac3e6655e6 | |||
0610ee434b | |||
a4f1463314 | |||
6183c034c6 | |||
2a985509fb | |||
cafd8096fa | |||
9f3ca37929 | |||
263c652d68 | |||
7b27ec0ea3 | |||
c49fac5ce5 | |||
fd63e995ff | |||
ad3bd451ba | |||
74bce1ecf9 | |||
d80703ac68 | |||
470212411d | |||
5146fdf368 | |||
860dd66431 | |||
efa1dcfc8f | |||
3f6135f427 | |||
1b1a592a1e | |||
a84cd4e8e3 | |||
a0a7f756c4 | |||
7296ebd2f8 | |||
d416eef144 | |||
fce6b91b97 | |||
c57ac26b2d | |||
9f47509dcb | |||
428361c46c | |||
261725dc0f | |||
b18f6beba9 | |||
cbc9728c02 | |||
9576c0ba1d | |||
1fe367a96c | |||
28cff3ed43 | |||
491b5e4ee9 | |||
64994ee44e | |||
e57974ebcd | |||
324f5e756c | |||
2b549227a6 | |||
61986c9b51 | |||
4d234cf832 | |||
7866ddbe06 | |||
fdcab1acb2 | |||
40fe1093e0 | |||
d3ae53cd46 | |||
|
67a66c0c44 | ||
a27a262858 | |||
ccc15aa048 | |||
891be91d69 | |||
56d13ebf9f | |||
7cebb74835 | |||
3f2fa286fb | |||
beae6e6ce0 | |||
cd2132ba45 | |||
666f05ff12 | |||
d784d8b1e2 | |||
3ee1eb3dec | |||
80a0312b1f | |||
6bf91afab9 | |||
6b60135867 | |||
50500e87b9 | |||
ce71ff2dd6 | |||
4ecd32f0ad | |||
a9c71a3384 | |||
cce7f59f4a | |||
b484fe6f64 | |||
50cc0c8e61 | |||
1b747ab99f | |||
45a1ba4fe1 | |||
037ec3b9dd | |||
454265cd6f | |||
ffdf5a2f18 | |||
1fa2635317 | |||
d58a7e819a | |||
26971459ac | |||
940b601061 | |||
bcd7f7b810 | |||
de07503bc3 | |||
bdb7381ab4 | |||
703f1f8cd5 | |||
b481bb0aa9 | |||
3a94b6191b | |||
19463963e3 | |||
02f60c2162 | |||
30e2da094a | |||
0e4a9ff7e0 | |||
9caf4c54ed | |||
98ee2ce771 | |||
73fc4aedcc | |||
88c1d100e9 | |||
f1cec2ced1 | |||
3bd7b879c4 | |||
ef44aa8830 | |||
acd45ce4ae | |||
ea0ef88068 | |||
e4d5dcd0a2 | |||
91f1c8c4f7 | |||
2963990b5e | |||
c456b24333 | |||
42e91409c7 | |||
e88684a564 | |||
7a9e7de138 | |||
480032a3d6 | |||
7db3b17090 | |||
5a5f653b86 | |||
4082c2abbf | |||
0e24344efd | |||
27ddad537f | |||
bc160a21b7 | |||
34e3bb0ead | |||
9edfcf6a3d | |||
939c6f4970 | |||
5472929113 | |||
545b8130e0 | |||
bf538d9bd0 | |||
2bdba0af22 | |||
ac61225730 | |||
9e8f988ea6 | |||
b396ec47b4 | |||
beab400873 | |||
f266924a9a | |||
b68456e6f4 | |||
4881f6bdd2 | |||
eeb1955ebe | |||
e2e8a58c4e | |||
2500572e0d | |||
59066ce09a | |||
038cb98f1a | |||
95af050517 | |||
12ca6fbfb5 | |||
d8d75c063b | |||
55c61cef98 | |||
|
c8680ae92c | ||
d2aea8559a | |||
8e2538e553 |
107 changed files with 4136 additions and 7577 deletions
|
@ -4,6 +4,7 @@ end_of_line = lf
|
|||
insert_final_newline = false
|
||||
indent_style = space
|
||||
indent_size = 4
|
||||
ij_any_field_annotation_wrap = off
|
||||
|
||||
[*.json]
|
||||
indent_style = space
|
||||
|
@ -12,6 +13,8 @@ indent_size = 2
|
|||
[*.java]
|
||||
indent_style = tab
|
||||
tab_width = 4
|
||||
ij_java_do_not_wrap_after_single_annotation = true
|
||||
ij_java_field_annotation_wrap = off
|
||||
|
||||
[{*.yml, *.yaml}]
|
||||
indent_style = space
|
||||
|
|
451
.gitignore
vendored
451
.gitignore
vendored
|
@ -1,225 +1,226 @@
|
|||
#################
|
||||
## Eclipse
|
||||
#################
|
||||
|
||||
*.pydevproject
|
||||
.metadata/
|
||||
bin/
|
||||
tmp/
|
||||
*.tmp
|
||||
*.bak
|
||||
*.swp
|
||||
*~.nib
|
||||
local.properties
|
||||
.classpath
|
||||
.settings/
|
||||
.loadpath
|
||||
target/
|
||||
.project
|
||||
|
||||
# External tool builders
|
||||
.externalToolBuilders/
|
||||
|
||||
# Locally stored "Eclipse launch configurations"
|
||||
*.launch
|
||||
|
||||
# CDT-specific
|
||||
.cproject
|
||||
|
||||
# PDT-specific
|
||||
.buildpath
|
||||
|
||||
|
||||
#################
|
||||
## Visual Studio
|
||||
#################
|
||||
|
||||
## Ignore Visual Studio temporary files, build results, and
|
||||
## files generated by popular Visual Studio add-ons.
|
||||
|
||||
# User-specific files
|
||||
*.suo
|
||||
*.user
|
||||
*.sln.docstates
|
||||
|
||||
# Build results
|
||||
|
||||
[Dd]ebug/
|
||||
[Rr]elease/
|
||||
x64/
|
||||
build/
|
||||
[Bb]in/
|
||||
[Oo]bj/
|
||||
|
||||
# MSTest test Results
|
||||
[Tt]est[Rr]esult*/
|
||||
[Bb]uild[Ll]og.*
|
||||
|
||||
*_i.c
|
||||
*_p.c
|
||||
*.ilk
|
||||
*.meta
|
||||
*.obj
|
||||
*.pch
|
||||
*.pdb
|
||||
*.pgc
|
||||
*.pgd
|
||||
*.rsp
|
||||
*.sbr
|
||||
*.tlb
|
||||
*.tli
|
||||
*.tlh
|
||||
*.tmp
|
||||
*.tmp_proj
|
||||
*.log
|
||||
*.vspscc
|
||||
*.vssscc
|
||||
.builds
|
||||
*.pidb
|
||||
*.log
|
||||
*.scc
|
||||
|
||||
# Visual C++ cache files
|
||||
ipch/
|
||||
*.aps
|
||||
*.ncb
|
||||
*.opensdf
|
||||
*.sdf
|
||||
*.cachefile
|
||||
|
||||
# Visual Studio profiler
|
||||
*.psess
|
||||
*.vsp
|
||||
*.vspx
|
||||
|
||||
# Guidance Automation Toolkit
|
||||
*.gpState
|
||||
|
||||
# ReSharper is a .NET coding add-in
|
||||
_ReSharper*/
|
||||
*.[Rr]e[Ss]harper
|
||||
|
||||
# TeamCity is a build add-in
|
||||
_TeamCity*
|
||||
|
||||
# DotCover is a Code Coverage Tool
|
||||
*.dotCover
|
||||
|
||||
# NCrunch
|
||||
*.ncrunch*
|
||||
.*crunch*.local.xml
|
||||
|
||||
# Installshield output folder
|
||||
[Ee]xpress/
|
||||
|
||||
# DocProject is a documentation generator add-in
|
||||
DocProject/buildhelp/
|
||||
DocProject/Help/*.HxT
|
||||
DocProject/Help/*.HxC
|
||||
DocProject/Help/*.hhc
|
||||
DocProject/Help/*.hhk
|
||||
DocProject/Help/*.hhp
|
||||
DocProject/Help/Html2
|
||||
DocProject/Help/html
|
||||
|
||||
# Click-Once directory
|
||||
publish/
|
||||
|
||||
# Publish Web Output
|
||||
*.Publish.xml
|
||||
*.pubxml
|
||||
*.publishproj
|
||||
|
||||
# NuGet Packages Directory
|
||||
## TO!DO: If you have NuGet Package Restore enabled, uncomment the next line
|
||||
#packages/
|
||||
|
||||
# Windows Azure Build Output
|
||||
csx
|
||||
*.build.csdef
|
||||
|
||||
# Windows Store app package directory
|
||||
AppPackages/
|
||||
|
||||
# Others
|
||||
sql/
|
||||
*.Cache
|
||||
ClientBin/
|
||||
[Ss]tyle[Cc]op.*
|
||||
~$*
|
||||
*~
|
||||
*.dbmdl
|
||||
*.[Pp]ublish.xml
|
||||
*.pfx
|
||||
*.publishsettings
|
||||
|
||||
# RIA/Silverlight projects
|
||||
Generated_Code/
|
||||
|
||||
# Backup & report files from converting an old project file to a newer
|
||||
# Visual Studio version. Backup files are not needed, because we have git ;-)
|
||||
_UpgradeReport_Files/
|
||||
Backup*/
|
||||
UpgradeLog*.XML
|
||||
UpgradeLog*.htm
|
||||
|
||||
# SQL Server files
|
||||
App_Data/*.mdf
|
||||
App_Data/*.ldf
|
||||
|
||||
#############
|
||||
## Windows detritus
|
||||
#############
|
||||
|
||||
# Windows image file caches
|
||||
Thumbs.db
|
||||
ehthumbs.db
|
||||
|
||||
# Folder config file
|
||||
Desktop.ini
|
||||
|
||||
# Recycle Bin used on file shares
|
||||
$RECYCLE.BIN/
|
||||
|
||||
# Mac crap
|
||||
.DS_Store
|
||||
|
||||
|
||||
#############
|
||||
## Python
|
||||
#############
|
||||
|
||||
*.py[cod]
|
||||
|
||||
# Packages
|
||||
*.egg
|
||||
*.egg-info
|
||||
dist/
|
||||
build/
|
||||
eggs/
|
||||
parts/
|
||||
var/
|
||||
sdist/
|
||||
develop-eggs/
|
||||
.installed.cfg
|
||||
|
||||
# Installer logs
|
||||
pip-log.txt
|
||||
|
||||
# Unit test / coverage reports
|
||||
.coverage
|
||||
.tox
|
||||
|
||||
#Translations
|
||||
*.mo
|
||||
|
||||
#Mr Developer
|
||||
.mr.developer.cfg
|
||||
.metadata/*
|
||||
TheButtonAutoFlair/out/artifacts/Autoflair/Autoflair.jar
|
||||
*.iml
|
||||
*.name
|
||||
.idea/compiler.xml
|
||||
*.xml
|
||||
|
||||
Token.txt
|
||||
#################
|
||||
## Eclipse
|
||||
#################
|
||||
|
||||
*.pydevproject
|
||||
.metadata/
|
||||
bin/
|
||||
tmp/
|
||||
*.tmp
|
||||
*.bak
|
||||
*.swp
|
||||
*~.nib
|
||||
local.properties
|
||||
.classpath
|
||||
.settings/
|
||||
.loadpath
|
||||
target/
|
||||
.project
|
||||
|
||||
# External tool builders
|
||||
.externalToolBuilders/
|
||||
|
||||
# Locally stored "Eclipse launch configurations"
|
||||
*.launch
|
||||
|
||||
# CDT-specific
|
||||
.cproject
|
||||
|
||||
# PDT-specific
|
||||
.buildpath
|
||||
|
||||
|
||||
#################
|
||||
## Visual Studio
|
||||
#################
|
||||
|
||||
## Ignore Visual Studio temporary files, build results, and
|
||||
## files generated by popular Visual Studio add-ons.
|
||||
|
||||
# User-specific files
|
||||
*.suo
|
||||
*.user
|
||||
*.sln.docstates
|
||||
|
||||
# Build results
|
||||
|
||||
[Dd]ebug/
|
||||
[Rr]elease/
|
||||
x64/
|
||||
build/
|
||||
[Bb]in/
|
||||
[Oo]bj/
|
||||
|
||||
# MSTest test Results
|
||||
[Tt]est[Rr]esult*/
|
||||
[Bb]uild[Ll]og.*
|
||||
|
||||
*_i.c
|
||||
*_p.c
|
||||
*.ilk
|
||||
*.meta
|
||||
*.obj
|
||||
*.pch
|
||||
*.pdb
|
||||
*.pgc
|
||||
*.pgd
|
||||
*.rsp
|
||||
*.sbr
|
||||
*.tlb
|
||||
*.tli
|
||||
*.tlh
|
||||
*.tmp
|
||||
*.tmp_proj
|
||||
*.log
|
||||
*.vspscc
|
||||
*.vssscc
|
||||
.builds
|
||||
*.pidb
|
||||
*.log
|
||||
*.scc
|
||||
|
||||
# Visual C++ cache files
|
||||
ipch/
|
||||
*.aps
|
||||
*.ncb
|
||||
*.opensdf
|
||||
*.sdf
|
||||
*.cachefile
|
||||
|
||||
# Visual Studio profiler
|
||||
*.psess
|
||||
*.vsp
|
||||
*.vspx
|
||||
|
||||
# Guidance Automation Toolkit
|
||||
*.gpState
|
||||
|
||||
# ReSharper is a .NET coding add-in
|
||||
_ReSharper*/
|
||||
*.[Rr]e[Ss]harper
|
||||
|
||||
# TeamCity is a build add-in
|
||||
_TeamCity*
|
||||
|
||||
# DotCover is a Code Coverage Tool
|
||||
*.dotCover
|
||||
|
||||
# NCrunch
|
||||
*.ncrunch*
|
||||
.*crunch*.local.xml
|
||||
|
||||
# Installshield output folder
|
||||
[Ee]xpress/
|
||||
|
||||
# DocProject is a documentation generator add-in
|
||||
DocProject/buildhelp/
|
||||
DocProject/Help/*.HxT
|
||||
DocProject/Help/*.HxC
|
||||
DocProject/Help/*.hhc
|
||||
DocProject/Help/*.hhk
|
||||
DocProject/Help/*.hhp
|
||||
DocProject/Help/Html2
|
||||
DocProject/Help/html
|
||||
|
||||
# Click-Once directory
|
||||
publish/
|
||||
|
||||
# Publish Web Output
|
||||
*.Publish.xml
|
||||
*.pubxml
|
||||
*.publishproj
|
||||
|
||||
# NuGet Packages Directory
|
||||
## TO!DO: If you have NuGet Package Restore enabled, uncomment the next line
|
||||
#packages/
|
||||
|
||||
# Windows Azure Build Output
|
||||
csx
|
||||
*.build.csdef
|
||||
|
||||
# Windows Store app package directory
|
||||
AppPackages/
|
||||
|
||||
# Others
|
||||
sql/
|
||||
*.Cache
|
||||
ClientBin/
|
||||
[Ss]tyle[Cc]op.*
|
||||
~$*
|
||||
*~
|
||||
*.dbmdl
|
||||
*.[Pp]ublish.xml
|
||||
*.pfx
|
||||
*.publishsettings
|
||||
|
||||
# RIA/Silverlight projects
|
||||
Generated_Code/
|
||||
|
||||
# Backup & report files from converting an old project file to a newer
|
||||
# Visual Studio version. Backup files are not needed, because we have git ;-)
|
||||
_UpgradeReport_Files/
|
||||
Backup*/
|
||||
UpgradeLog*.XML
|
||||
UpgradeLog*.htm
|
||||
|
||||
# SQL Server files
|
||||
App_Data/*.mdf
|
||||
App_Data/*.ldf
|
||||
|
||||
#############
|
||||
## Windows detritus
|
||||
#############
|
||||
|
||||
# Windows image file caches
|
||||
Thumbs.db
|
||||
ehthumbs.db
|
||||
|
||||
# Folder config file
|
||||
Desktop.ini
|
||||
|
||||
# Recycle Bin used on file shares
|
||||
$RECYCLE.BIN/
|
||||
|
||||
# Mac crap
|
||||
.DS_Store
|
||||
|
||||
|
||||
#############
|
||||
## Python
|
||||
#############
|
||||
|
||||
*.py[cod]
|
||||
|
||||
# Packages
|
||||
*.egg
|
||||
*.egg-info
|
||||
dist/
|
||||
build/
|
||||
eggs/
|
||||
parts/
|
||||
var/
|
||||
sdist/
|
||||
develop-eggs/
|
||||
.installed.cfg
|
||||
|
||||
# Installer logs
|
||||
pip-log.txt
|
||||
|
||||
# Unit test / coverage reports
|
||||
.coverage
|
||||
.tox
|
||||
|
||||
#Translations
|
||||
*.mo
|
||||
|
||||
#Mr Developer
|
||||
.mr.developer.cfg
|
||||
.metadata/*
|
||||
TheButtonAutoFlair/out/artifacts/Autoflair/Autoflair.jar
|
||||
*.iml
|
||||
*.name
|
||||
.idea/compiler.xml
|
||||
*.xml
|
||||
|
||||
Token.txt
|
||||
.bsp
|
||||
|
|
21
.travis.yml
21
.travis.yml
|
@ -2,25 +2,24 @@ cache:
|
|||
directories:
|
||||
- $HOME/.m2/repository/org/
|
||||
before_install: | # Wget BuildTools and run if cached folder not found
|
||||
export JAVA_HOME=$HOME/oraclejdk8
|
||||
~/bin/install-jdk.sh --install oraclejdk8 --target $JAVA_HOME
|
||||
if [ ! -d "$HOME/.m2/repository/org/spigotmc/spigot/1.12.2-R0.1-SNAPSHOT" ]; then
|
||||
wget -O BuildTools.jar https://hub.spigotmc.org/jenkins/job/BuildTools/lastSuccessfulBuild/artifact/target/BuildTools.jar
|
||||
# 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*$"
|
||||
fi
|
||||
export JAVA_HOME=$HOME/oraclejdk11
|
||||
~/bin/install-jdk.sh --install oraclejdk11 --target $JAVA_HOME
|
||||
language: java
|
||||
jdk:
|
||||
- oraclejdk8
|
||||
- oraclejdk11
|
||||
sudo: true
|
||||
deploy:
|
||||
# deploy develop to the staging environment
|
||||
- provider: script
|
||||
script: chmod +x deploy.sh && sh deploy.sh staging
|
||||
- provider: releases
|
||||
api_key:
|
||||
secure: "AnGhHbIFAdfFEtxuAv3Bue5n80JJi9FMyXc2rstg1zzBbuvaYqCUWcL7lB34Ffs9E6Mo5wfANnBRyXtdSfXWLLsb0k78vvlAwJyLP2s0V7r9LTvQWJEflslSDX6ySF0YIc3LR+XMYv+qj+e5XnWr6Kj6gRkaQPDzSIYRgvfKZv9fbo4lSqnp2OcOrn4sYyeV6+sLhARLaNTvbDOdLiMRP3JZUrKB4OCt8+XhrVMlwKhglJY8JVKx1uAFxeljfZ3WJ1WnJ6L8coyVR18HAl1/VHwn+a/jeGp9AygTPF2yJL3+TJs37afqG9jjbL0pneSUoyNenKkjD19pM2RgjGmW25kPEvnmGMaWn8UN8bbilB5k8sh27z+/6qNnvYbhJxJi9RJNASpd6JQ1cGZoBziKsvhkLXErRNCJ92wlgGOqE78UWf6dvzmVkQD/vaqXhHlmcVhpoUZUqsXGWw5gOw/Kxh90IUwsV6A2JXf1Q3YRPIfDin/tVpud6eB0hiRW2uLnAqDMUUsH6n8cqd2rzg/02uKD5rF5+amxfdUSf3m/Fh6lqklNlO1188rFULUPpyFRas59UpEIRqT2Ae9OJPg+1QrVln2Gd3l059MHumX2tidQl00GzXx4nB1NkxpKLl9JLf/n6A4MQodY5CkRELUTB8K3zHGhJdj1Dtmis5YwhXk="
|
||||
file: 'target/Chroma-Discord.jar'
|
||||
on:
|
||||
branch: dev
|
||||
skip_cleanup: true
|
||||
# deploy master to production
|
||||
- provider: script
|
||||
script: chmod +x deploy.sh && sh deploy.sh production
|
||||
on:
|
||||
branch: master
|
||||
tags: true
|
||||
skip_cleanup: true
|
||||
|
|
17
README.md
17
README.md
|
@ -1,11 +1,10 @@
|
|||
# DiscordPlugin
|
||||
A plugin that controls the ChromaBot Discord bot and provides Minecraft chat functionality and other features.
|
||||
# Chroma-Discord
|
||||
A plugin that provides Minecraft chat functionality and other features.
|
||||
|
||||
## Features
|
||||
### Announce new posts from /r/ChromaGamers
|
||||
If it's a (distinguished) moderator post, it'll be posted to the \#announcements channel, otherwise it'll be posted and pinned to \#general.
|
||||
## Setup
|
||||
This plugin needs Chroma-Core to work. If you have that and this plugin, start the server, and follow the instructions.
|
||||
You'll need a Discord application made, and a bot account created for it.
|
||||
You can restart the plugin using /discord restart without having to restart the whole server.
|
||||
|
||||
### Announce server restarts
|
||||
It announces server starts/stops and restarts, as well as if the server shut down unexpectedly.
|
||||
|
||||
**For more, see:** http://chromapedia.wikia.com/wiki/ChromaBot
|
||||
## Building
|
||||
Maven is used to build this project with all of its dependencies. You will need Spigot 1.12.2 and 1.14.4 built using BuildTools.
|
||||
|
|
67
build.sbt
Normal file
67
build.sbt
Normal file
|
@ -0,0 +1,67 @@
|
|||
name := "Chroma-Discord"
|
||||
|
||||
version := "1.1"
|
||||
|
||||
scalaVersion := "2.13.11"
|
||||
|
||||
resolvers += "jitpack.io" at "https://jitpack.io"
|
||||
resolvers += "paper-repo" at "https://papermc.io/repo/repository/maven-public/"
|
||||
resolvers += Resolver.mavenLocal
|
||||
|
||||
// assembly / assemblyOption := (assembly / assemblyOption).value.copy(includeScala = false)
|
||||
|
||||
libraryDependencies ++= Seq(
|
||||
"io.papermc.paper" % "paper-api" % "1.19-R0.1-SNAPSHOT" % Provided,
|
||||
|
||||
"com.discord4j" % "discord4j-core" % "3.2.3",
|
||||
"com.vdurmont" % "emoji-java" % "5.1.1",
|
||||
"io.projectreactor" % "reactor-scala-extensions_2.13" % "0.8.0",
|
||||
|
||||
"com.github.TBMCPlugins.ChromaCore" % "Chroma-Core" % "v2.0.0-SNAPSHOT" % Provided,
|
||||
"net.ess3" % "EssentialsX" % "2.17.1" % Provided,
|
||||
// https://mvnrepository.com/artifact/com.mojang/brigadier
|
||||
"com.mojang" % "brigadier" % "1.0.500" % "provided",
|
||||
// https://mvnrepository.com/artifact/net.kyori/examination-api
|
||||
"net.kyori" % "examination-api" % "1.3.0" % "provided",
|
||||
// https://mvnrepository.com/artifact/org.jetbrains.kotlin/kotlin-stdlib
|
||||
//"org.jetbrains.kotlin" % "kotlin-stdlib" % "1.8.20" % "provided",
|
||||
// https://mvnrepository.com/artifact/org.scalatest/scalatest
|
||||
"org.scalatest" %% "scalatest" % "3.2.16" % Test,
|
||||
// https://mvnrepository.com/artifact/com.github.seeseemelk/MockBukkit-v1.19
|
||||
"com.github.seeseemelk" % "MockBukkit-v1.19" % "2.29.0" % Test,
|
||||
"com.github.milkbowl" % "vault" % "master-SNAPSHOT" % Test
|
||||
)
|
||||
|
||||
assembly / assemblyJarName := "Chroma-Discord.jar"
|
||||
assembly / assemblyShadeRules := Seq(
|
||||
"io.netty", "com.fasterxml", "org.slf4j"
|
||||
).map { p =>
|
||||
ShadeRule.rename(s"$p.**" -> "btndvtm.dp.@0").inAll
|
||||
}
|
||||
|
||||
assembly / assemblyMergeStrategy := {
|
||||
case PathList("META-INF", "io.netty.versions.properties") => MergeStrategy.concat
|
||||
// https://stackoverflow.com/a/55557287/457612
|
||||
case "module-info.class" => MergeStrategy.discard
|
||||
case "META-INF/versions/9/module-info.class" => MergeStrategy.discard
|
||||
case x => (assembly / assemblyMergeStrategy).value(x)
|
||||
}
|
||||
|
||||
val saveConfigComments = TaskKey[Seq[File]]("saveConfigComments")
|
||||
saveConfigComments := {
|
||||
Commenter.saveConfigComments((Compile / sources).value)
|
||||
}
|
||||
|
||||
Compile / resourceGenerators += saveConfigComments
|
||||
//scalacOptions ++= Seq("-release", "17", "--verbose")
|
||||
scalacOptions ++= Seq("-release", "17")
|
||||
//Test / classLoaderLayeringStrategy := ClassLoaderLayeringStrategy.Flat
|
||||
Test / fork := true // This changes the tests ran through sbt to work like IntelliJ tests, fixes mocking issues
|
||||
/*excludeDependencies ++= Seq(
|
||||
ExclusionRule("org.bukkit"),
|
||||
ExclusionRule("io.papermc.paper"),
|
||||
ExclusionRule("com.destroystokyo")
|
||||
)*/
|
||||
excludeDependencies ++= Seq(
|
||||
ExclusionRule("net.milkbowl.vault", "VaultAPI")
|
||||
)
|
|
@ -1 +0,0 @@
|
|||
lombok.var.flagUsage = ALLOW
|
246
pom.xml
246
pom.xml
|
@ -1,246 +0,0 @@
|
|||
<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">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<groupId>com.github.TBMCPlugins</groupId>
|
||||
<artifactId>DiscordPlugin</artifactId>
|
||||
<version>master-SNAPSHOT</version>
|
||||
<packaging>jar</packaging>
|
||||
|
||||
<name>DiscordPlugin</name>
|
||||
<url>http://maven.apache.org</url>
|
||||
|
||||
<build>
|
||||
<!-- <sourceDirectory>target/generated-sources/delombok</sourceDirectory>
|
||||
<testSourceDirectory>target/generated-test-sources/delombok</testSourceDirectory> -->
|
||||
<sourceDirectory>src/main/java</sourceDirectory>
|
||||
<resources>
|
||||
<resource>
|
||||
<directory>src</directory>
|
||||
<excludes>
|
||||
<exclude>**/*.java</exclude>
|
||||
</excludes>
|
||||
</resource>
|
||||
<resource>
|
||||
<directory>src/main/resources</directory>
|
||||
<includes>
|
||||
<include>*.properties</include>
|
||||
<include>*.yml</include>
|
||||
<include>*.csv</include>
|
||||
<include>*.txt</include>
|
||||
</includes>
|
||||
<filtering>true</filtering>
|
||||
</resource>
|
||||
</resources>
|
||||
<finalName>DiscordPlugin</finalName>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<artifactId>maven-compiler-plugin</artifactId>
|
||||
<version>3.6.2</version>
|
||||
<configuration>
|
||||
<source>1.8</source>
|
||||
<target>1.8</target>
|
||||
</configuration>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-shade-plugin</artifactId>
|
||||
<version>2.4.2</version>
|
||||
<executions>
|
||||
<execution>
|
||||
<phase>package</phase>
|
||||
<goals>
|
||||
<goal>shade</goal>
|
||||
</goals>
|
||||
<configuration>
|
||||
<artifactSet>
|
||||
<excludes>
|
||||
<exclude>org.spigotmc:spigot-api</exclude>
|
||||
<exclude>com.github.TBMCPlugins.ButtonCore:ButtonCore</exclude>
|
||||
<exclude>net.ess3:Essentials</exclude>
|
||||
</excludes> <!-- http://stackoverflow.com/questions/28458058/maven-shade-plugin-exclude-a-dependency-and-all-its-transitive-dependencies -->
|
||||
</artifactSet>
|
||||
</configuration>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-resources-plugin</artifactId>
|
||||
<version>3.0.1</version>
|
||||
<executions>
|
||||
<execution>
|
||||
<id>copy</id>
|
||||
<phase>compile</phase>
|
||||
<goals>
|
||||
<goal>copy-resources</goal>
|
||||
</goals>
|
||||
<configuration>
|
||||
<outputDirectory>target</outputDirectory>
|
||||
<resources>
|
||||
<resource>
|
||||
<directory>resources</directory>
|
||||
</resource>
|
||||
</resources>
|
||||
</configuration>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
<!-- <plugin> <groupId>org.projectlombok</groupId> <artifactId>lombok-maven-plugin</artifactId>
|
||||
<version>1.16.16.0</version> <executions> <execution> <id>delombok</id> <phase>generate-sources</phase>
|
||||
<goals> <goal>delombok</goal> </goals> <configuration> <addOutputDirectory>false</addOutputDirectory>
|
||||
<sourceDirectory>src/main/java</sourceDirectory> <verbose>true</verbose>
|
||||
</configuration> </execution> <execution> <id>test-delombok</id> <phase>generate-test-sources</phase>
|
||||
<goals> <goal>testDelombok</goal> </goals> <configuration> <addOutputDirectory>false</addOutputDirectory>
|
||||
<sourceDirectory>src/test/java</sourceDirectory> </configuration> </execution>
|
||||
</executions> </plugin> -->
|
||||
<plugin>
|
||||
<artifactId>maven-surefire-plugin</artifactId>
|
||||
<configuration>
|
||||
<useSystemClassLoader>false
|
||||
</useSystemClassLoader> <!-- https://stackoverflow.com/a/53012553/2703239 -->
|
||||
</configuration>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
|
||||
<properties>
|
||||
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||
<branch>
|
||||
master
|
||||
</branch> <!-- Should be master if building ButtonCore locally - the CI will overwrite it (see below) -->
|
||||
</properties>
|
||||
|
||||
<repositories>
|
||||
<repository>
|
||||
<id>spigot-repo</id>
|
||||
<url>https://hub.spigotmc.org/nexus/content/repositories/snapshots/</url>
|
||||
</repository>
|
||||
<repository> <!-- This repo fixes issues with transitive dependencies -->
|
||||
<id>jcenter</id>
|
||||
<url>http://jcenter.bintray.com</url>
|
||||
</repository>
|
||||
<repository>
|
||||
<id>jitpack.io</id>
|
||||
<url>https://jitpack.io</url>
|
||||
</repository>
|
||||
<!-- <repository>
|
||||
<id>vault-repo</id>
|
||||
<url>http://nexus.hc.to/content/repositories/pub_releases</url>
|
||||
</repository> -->
|
||||
<repository>
|
||||
<id>Essentials</id>
|
||||
<url>http://repo.ess3.net/content/repositories/essrel/</url>
|
||||
</repository>
|
||||
<repository>
|
||||
<id>projectlombok.org</id>
|
||||
<url>http://projectlombok.org/mavenrepo</url>
|
||||
</repository>
|
||||
<!-- <repository>
|
||||
<id>pex-repo</id>
|
||||
<url>http://pex-repo.aoeu.xyz</url>
|
||||
</repository> -->
|
||||
</repositories>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>junit</groupId>
|
||||
<artifactId>junit</artifactId>
|
||||
<version>3.8.1</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.spigotmc</groupId>
|
||||
<artifactId>spigot-api</artifactId>
|
||||
<version>1.12-R0.1-SNAPSHOT</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.spigotmc</groupId>
|
||||
<artifactId>spigot</artifactId>
|
||||
<version>1.12.2-R0.1-SNAPSHOT</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<!-- https://mvnrepository.com/artifact/com.discord4j/Discord4J -->
|
||||
<dependency>
|
||||
<groupId>com.discord4j</groupId>
|
||||
<artifactId>Discord4J</artifactId>
|
||||
<version>2.10.1</version>
|
||||
</dependency>
|
||||
<!-- https://mvnrepository.com/artifact/org.slf4j/slf4j-jdk14 -->
|
||||
<dependency>
|
||||
<groupId>org.slf4j</groupId>
|
||||
<artifactId>slf4j-jdk14</artifactId>
|
||||
<version>1.7.21</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.github.TBMCPlugins.ButtonCore</groupId>
|
||||
<artifactId>ButtonCore</artifactId>
|
||||
<version>${branch}-SNAPSHOT</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.github.milkbowl</groupId> <!-- net.milkbowl.vault -->
|
||||
<artifactId>VaultAPI</artifactId>
|
||||
<version>master-SNAPSHOT</version> <!-- 1.6 -->
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>net.ess3</groupId>
|
||||
<artifactId>Essentials</artifactId>
|
||||
<version>2.13.1</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.github.xaanit</groupId>
|
||||
<artifactId>D4J-OAuth</artifactId>
|
||||
<version>master-SNAPSHOT</version>
|
||||
</dependency>
|
||||
<!-- https://mvnrepository.com/artifact/org.projectlombok/lombok -->
|
||||
<dependency>
|
||||
<groupId>org.projectlombok</groupId>
|
||||
<artifactId>lombok</artifactId>
|
||||
<version>1.16.16</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<!-- <dependency>
|
||||
<groupId>ru.tehkode</groupId>
|
||||
<artifactId>PermissionsEx</artifactId>
|
||||
<version>1.23.1</version>
|
||||
<scope>provided</scope>
|
||||
<exclusions>
|
||||
<exclusion>
|
||||
<groupId>org.bukkit</groupId>
|
||||
<artifactId>bukkit</artifactId>
|
||||
</exclusion>
|
||||
</exclusions>
|
||||
</dependency> -->
|
||||
<!-- https://mvnrepository.com/artifact/org.objenesis/objenesis -->
|
||||
<dependency>
|
||||
<groupId>org.objenesis</groupId>
|
||||
<artifactId>objenesis</artifactId>
|
||||
<version>2.6</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.vdurmont</groupId>
|
||||
<artifactId>emoji-java</artifactId>
|
||||
<version>4.0.0</version>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
<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>
|
96
project/Commenter.scala
Normal file
96
project/Commenter.scala
Normal file
|
@ -0,0 +1,96 @@
|
|||
import java.util.regex.Pattern
|
||||
import sbt.*
|
||||
import org.bukkit.configuration.file.YamlConfiguration
|
||||
import scala.io.Source
|
||||
import scala.util.Using
|
||||
|
||||
object Commenter {
|
||||
def saveConfigComments(sv: Seq[File]): Seq[File] = {
|
||||
val cdataRegex = Pattern.compile("(?:def|val|var) (\\w+)(?::[^=]+)? = (?:getI?Config|DPUtils.\\w+Data)") //Hack: DPUtils
|
||||
val clRegex = Pattern.compile("class (\\w+).* extends ((?:\\w|\\d)+)")
|
||||
val objRegex = Pattern.compile("object (\\w+)")
|
||||
val subRegex = Pattern.compile("def `?(\\w+)`?")
|
||||
val subParamRegex = Pattern.compile("((?:\\w|\\d)+): ((?:\\w|\\d)+)")
|
||||
val configConfig = new YamlConfiguration()
|
||||
val commandConfig = new YamlConfiguration()
|
||||
|
||||
def getConfigComments(line: String, clKey: String, comment: String, justCommented: Boolean): (String, String, Boolean) = {
|
||||
val clMatcher = clRegex.matcher(line)
|
||||
if (clKey == null && clMatcher.find()) { //First occurrence
|
||||
(if (clMatcher.group(2).contains("Component"))
|
||||
"components." + clMatcher.group(1)
|
||||
else "global", comment, justCommented)
|
||||
} else if (line.contains("/**")) {
|
||||
(clKey, "", false)
|
||||
} else if (line.contains("*/") && comment != null)
|
||||
(clKey, comment, true)
|
||||
else if (comment != null) {
|
||||
if (justCommented) {
|
||||
if (clKey != null) {
|
||||
val matcher = cdataRegex.matcher(line)
|
||||
if (matcher.find())
|
||||
configConfig.set(s"$clKey.${matcher.group(1)}", comment.trim)
|
||||
}
|
||||
else {
|
||||
val matcher = objRegex.matcher(line)
|
||||
if (matcher.find()) {
|
||||
val clName = matcher.group(1)
|
||||
val compKey = if (clName.contains("Module")) s"component.$clName"
|
||||
else if (clName.contains("Plugin")) "global"
|
||||
else null
|
||||
if (compKey != null)
|
||||
configConfig.set(s"$compKey.generalDescriptionInsteadOfAConfig", comment.trim)
|
||||
}
|
||||
}
|
||||
(clKey, null, false)
|
||||
}
|
||||
else (clKey, comment + line.replaceFirst("^\\s*\\*\\s+", "") + "\n", justCommented)
|
||||
}
|
||||
else (clKey, comment, justCommented)
|
||||
}
|
||||
|
||||
for (file <- sv) {
|
||||
Using(Source.fromFile(file)) { src =>
|
||||
var clKey: String = null
|
||||
var comment: String = null
|
||||
var justCommented: Boolean = false
|
||||
|
||||
var subCommand = false
|
||||
var pkg: String = null
|
||||
var clName: String = null
|
||||
for (line <- src.getLines) {
|
||||
val (clk, c, jc) = getConfigComments(line, clKey, comment, justCommented)
|
||||
clKey = clk; comment = c; justCommented = jc
|
||||
|
||||
val objMatcher = objRegex.matcher(line)
|
||||
val clMatcher = clRegex.matcher(line)
|
||||
if (pkg == null && line.startsWith("package "))
|
||||
pkg = line.substring("package ".length)
|
||||
else if (clName == null && objMatcher.find())
|
||||
clName = objMatcher.group(1)
|
||||
else if (clName == null && clMatcher.find())
|
||||
clName = clMatcher.group(1)
|
||||
val subMatcher = subRegex.matcher(line)
|
||||
val subParamMatcher = subParamRegex.matcher(line)
|
||||
val sub = line.contains("@Subcommand") || line.contains("@Command2.Subcommand")
|
||||
if (sub) subCommand = true
|
||||
else if (line.contains("}")) subCommand = false
|
||||
if (subCommand && subMatcher.find()) {
|
||||
/*val groups = (2 to subMatcher.groupCount()).map(subMatcher.group)
|
||||
val pairs = for (i <- groups.indices by 2) yield (groups(i), groups(i + 1))*/
|
||||
val mname = subMatcher.group(1)
|
||||
val params = Iterator.continually(()).takeWhile(_ => subParamMatcher.find())
|
||||
.map(_ => subParamMatcher.group(1)).drop(1)
|
||||
val section = commandConfig.createSection(s"$pkg.$clName.$mname")
|
||||
section.set("method", s"$mname()")
|
||||
section.set("params", params.mkString(" "))
|
||||
subCommand = false
|
||||
}
|
||||
}
|
||||
configConfig.save("target/configHelp.yml")
|
||||
commandConfig.save("target/commands.yml")
|
||||
}.recover[Unit]({ case t => t.printStackTrace() })
|
||||
}
|
||||
Seq(file("target/configHelp.yml"), file("target/commands.yml"))
|
||||
}
|
||||
}
|
2
project/build.properties
Normal file
2
project/build.properties
Normal file
|
@ -0,0 +1,2 @@
|
|||
sbt.version=1.8.2
|
||||
scala.version=2.13.11
|
7
project/build.sbt
Normal file
7
project/build.sbt
Normal file
|
@ -0,0 +1,7 @@
|
|||
//lazy val commenter = RootProject(file("../commenter"))
|
||||
//lazy val root = (project in file(".")).dependsOn(commenter)
|
||||
|
||||
resolvers += Resolver.mavenLocal
|
||||
resolvers += "paper-repo" at "https://papermc.io/repo/repository/maven-public/"
|
||||
|
||||
libraryDependencies += "io.papermc.paper" % "paper-api" % "1.19.4-R0.1-SNAPSHOT" % Compile
|
1
project/plugins.sbt
Normal file
1
project/plugins.sbt
Normal file
|
@ -0,0 +1 @@
|
|||
addSbtPlugin("com.eed3si9n" % "sbt-assembly" % "2.1.1")
|
|
@ -1,27 +0,0 @@
|
|||
package buttondevteam.discordplugin;
|
||||
|
||||
import lombok.Getter;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.Setter;
|
||||
import org.bukkit.event.Cancellable;
|
||||
import org.bukkit.event.Event;
|
||||
import org.bukkit.event.HandlerList;
|
||||
|
||||
@RequiredArgsConstructor
|
||||
public class AsyncDiscordEvent<T extends sx.blah.discord.api.events.Event> extends Event implements Cancellable {
|
||||
private final @Getter T event;
|
||||
@Getter
|
||||
@Setter
|
||||
private boolean cancelled;
|
||||
|
||||
private static final HandlerList handlers = new HandlerList();
|
||||
|
||||
@Override
|
||||
public HandlerList getHandlers() {
|
||||
return handlers;
|
||||
}
|
||||
|
||||
public static HandlerList getHandlerList() {
|
||||
return handlers;
|
||||
}
|
||||
}
|
|
@ -1,15 +0,0 @@
|
|||
package buttondevteam.discordplugin;
|
||||
|
||||
public enum ChannelconBroadcast {
|
||||
JOINLEAVE,
|
||||
AFK,
|
||||
RESTART,
|
||||
DEATH,
|
||||
BROADCAST;
|
||||
|
||||
public final int flag;
|
||||
|
||||
ChannelconBroadcast() {
|
||||
this.flag = 1 << this.ordinal();
|
||||
}
|
||||
}
|
|
@ -1,146 +0,0 @@
|
|||
package buttondevteam.discordplugin;
|
||||
|
||||
import buttondevteam.discordplugin.mcchat.MCChatUtils;
|
||||
import lombok.Getter;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.scheduler.BukkitScheduler;
|
||||
import sx.blah.discord.api.internal.json.objects.EmbedObject;
|
||||
import sx.blah.discord.handle.obj.IChannel;
|
||||
import sx.blah.discord.util.EmbedBuilder;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
import java.awt.*;
|
||||
|
||||
public class ChromaBot {
|
||||
/**
|
||||
* May be null if it's not initialized. Initialization happens after the server is done loading (using {@link BukkitScheduler#runTaskAsynchronously(org.bukkit.plugin.Plugin, Runnable)})
|
||||
*/
|
||||
private static @Getter ChromaBot instance;
|
||||
private DiscordPlugin dp;
|
||||
|
||||
/**
|
||||
* This will set the instance field.
|
||||
*
|
||||
* @param dp
|
||||
* The Discord plugin
|
||||
*/
|
||||
ChromaBot(DiscordPlugin dp) {
|
||||
instance = this;
|
||||
this.dp = dp;
|
||||
}
|
||||
|
||||
static void delete() {
|
||||
instance = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Send a message to the chat channel and private chats.
|
||||
*
|
||||
* @param message
|
||||
* The message to send, duh
|
||||
*/
|
||||
public void sendMessage(String message) {
|
||||
MCChatUtils.forAllMCChat(ch -> DiscordPlugin.sendMessageToChannel(ch, message));
|
||||
}
|
||||
|
||||
/**
|
||||
* Send a message to the chat channels and private chats.
|
||||
*
|
||||
* @param message
|
||||
* The message to send, duh
|
||||
* @param embed
|
||||
* Custom fancy stuff, use {@link EmbedBuilder} to create one
|
||||
*/
|
||||
public void sendMessage(String message, EmbedObject embed) {
|
||||
MCChatUtils.forAllMCChat(ch -> DiscordPlugin.sendMessageToChannel(ch, message, embed));
|
||||
}
|
||||
|
||||
/**
|
||||
* Send a message to the chat channels, private chats and custom chats.
|
||||
*
|
||||
* @param message The message to send, duh
|
||||
* @param embed Custom fancy stuff, use {@link EmbedBuilder} to create one
|
||||
* @param toggle The toggle type for channelcon
|
||||
*/
|
||||
public void sendMessageCustomAsWell(String message, EmbedObject embed, @Nullable ChannelconBroadcast toggle) {
|
||||
MCChatUtils.forCustomAndAllMCChat(ch -> DiscordPlugin.sendMessageToChannel(ch, message, embed), toggle, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Send a message to an arbitrary channel. This will not send it to the private chats.
|
||||
*
|
||||
* @param channel
|
||||
* The channel to send to, use the channel variables in {@link DiscordPlugin}
|
||||
* @param message
|
||||
* The message to send, duh
|
||||
* @param embed
|
||||
* Custom fancy stuff, use {@link EmbedBuilder} to create one
|
||||
*/
|
||||
public void sendMessage(IChannel channel, String message, EmbedObject embed) {
|
||||
DiscordPlugin.sendMessageToChannel(channel, message, embed);
|
||||
}
|
||||
|
||||
/**
|
||||
* Send a fancy message to the chat channels. This will show a bold text with a colored line.
|
||||
*
|
||||
* @param message
|
||||
* The message to send, duh
|
||||
* @param color
|
||||
* The color of the line before the text
|
||||
*/
|
||||
public void sendMessage(String message, Color color) {
|
||||
MCChatUtils.forAllMCChat(ch -> DiscordPlugin.sendMessageToChannel(ch, message,
|
||||
new EmbedBuilder().withTitle(message).withColor(color).build()));
|
||||
}
|
||||
|
||||
/**
|
||||
* Send a fancy message to the chat channels. This will show a bold text with a colored line.
|
||||
*
|
||||
* @param message
|
||||
* The message to send, duh
|
||||
* @param color
|
||||
* The color of the line before the text
|
||||
* @param mcauthor
|
||||
* The name of the Minecraft player who is the author of this message
|
||||
*/
|
||||
public void sendMessage(String message, Color color, String mcauthor) {
|
||||
MCChatUtils.forAllMCChat(ch -> DiscordPlugin.sendMessageToChannel(ch, message,
|
||||
DPUtils.embedWithHead(new EmbedBuilder().withTitle(message).withColor(color), mcauthor).build()));
|
||||
}
|
||||
|
||||
/**
|
||||
* Send a fancy message to the chat channels. This will show a bold text with a colored line.
|
||||
*
|
||||
* @param message
|
||||
* The message to send, duh
|
||||
* @param color
|
||||
* The color of the line before the text
|
||||
* @param authorname
|
||||
* The name of the author of this message
|
||||
* @param authorimg
|
||||
* The URL of the avatar image for this message's author
|
||||
*/
|
||||
public void sendMessage(String message, Color color, String authorname, String authorimg) {
|
||||
MCChatUtils.forAllMCChat(ch -> DiscordPlugin.sendMessageToChannel(ch, message, new EmbedBuilder()
|
||||
.withTitle(message).withColor(color).withAuthorName(authorname).withAuthorIcon(authorimg).build()));
|
||||
}
|
||||
|
||||
/**
|
||||
* Send a message to the chat channels. This will show a bold text with a colored line.
|
||||
*
|
||||
* @param message
|
||||
* The message to send, duh
|
||||
* @param color
|
||||
* The color of the line before the text
|
||||
* @param sender
|
||||
* The player who sends this message
|
||||
*/
|
||||
public void sendMessage(String message, Color color, Player sender) {
|
||||
MCChatUtils.forAllMCChat(ch -> DiscordPlugin.sendMessageToChannel(ch, message, DPUtils
|
||||
.embedWithHead(new EmbedBuilder().withTitle(message).withColor(color), sender.getName()).build()));
|
||||
}
|
||||
|
||||
public void updatePlayerList() {
|
||||
MCChatUtils.updatePlayerList();
|
||||
}
|
||||
}
|
|
@ -1,171 +0,0 @@
|
|||
package buttondevteam.discordplugin;
|
||||
|
||||
import buttondevteam.lib.TBMCCoreAPI;
|
||||
import buttondevteam.lib.architecture.Component;
|
||||
import buttondevteam.lib.architecture.ConfigData;
|
||||
import buttondevteam.lib.architecture.IHaveConfig;
|
||||
import lombok.val;
|
||||
import org.bukkit.Bukkit;
|
||||
import sx.blah.discord.handle.obj.IChannel;
|
||||
import sx.blah.discord.handle.obj.IGuild;
|
||||
import sx.blah.discord.handle.obj.IIDLinkedObject;
|
||||
import sx.blah.discord.handle.obj.IRole;
|
||||
import sx.blah.discord.util.EmbedBuilder;
|
||||
import sx.blah.discord.util.RequestBuffer;
|
||||
import sx.blah.discord.util.RequestBuffer.IRequest;
|
||||
import sx.blah.discord.util.RequestBuffer.IVoidRequest;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.concurrent.TimeoutException;
|
||||
import java.util.logging.Logger;
|
||||
import java.util.regex.Matcher;
|
||||
|
||||
public final class DPUtils {
|
||||
|
||||
public static EmbedBuilder embedWithHead(EmbedBuilder builder, String playername) {
|
||||
return builder.withAuthorIcon("https://minotar.net/avatar/" + playername + "/32.png");
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes §[char] colour codes from strings & escapes them for Discord <br>
|
||||
* Ensure that this method only gets called once (escaping)
|
||||
*/
|
||||
public static String sanitizeString(String string) {
|
||||
return escape(sanitizeStringNoEscape(string));
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes §[char] colour codes from strings
|
||||
*/
|
||||
public static String sanitizeStringNoEscape(String string) {
|
||||
String sanitizedString = "";
|
||||
boolean random = false;
|
||||
for (int i = 0; i < string.length(); i++) {
|
||||
if (string.charAt(i) == '§') {
|
||||
i++;// Skips the data value, the 4 in "§4Alisolarflare"
|
||||
random = string.charAt(i) == 'k';
|
||||
} else {
|
||||
if (!random) // Skip random/obfuscated characters
|
||||
sanitizedString += string.charAt(i);
|
||||
}
|
||||
}
|
||||
return sanitizedString;
|
||||
}
|
||||
|
||||
/**
|
||||
* Performs Discord actions, retrying when ratelimited. May return null if action fails too many times or in safe mode.
|
||||
*/
|
||||
@Nullable
|
||||
public static <T> T perform(IRequest<T> action, long timeout, TimeUnit unit) throws TimeoutException, InterruptedException {
|
||||
if (DiscordPlugin.SafeMode)
|
||||
return null;
|
||||
if (Bukkit.isPrimaryThread()) // TODO: Ignore shutdown message <--
|
||||
// throw new RuntimeException("Tried to wait for a Discord request on the main thread. This could cause lag.");
|
||||
getLogger().warning("Waiting for a Discord request on the main thread!");
|
||||
return RequestBuffer.request(action).get(timeout, unit); // Let the pros handle this
|
||||
}
|
||||
|
||||
/**
|
||||
* Performs Discord actions, retrying when ratelimited. May return null if action fails too many times or in safe mode.
|
||||
*/
|
||||
@Nullable
|
||||
public static <T> T perform(IRequest<T> action) {
|
||||
if (DiscordPlugin.SafeMode)
|
||||
return null;
|
||||
if (Bukkit.isPrimaryThread()) // TODO: Ignore shutdown message <--
|
||||
// throw new RuntimeException("Tried to wait for a Discord request on the main thread. This could cause lag.");
|
||||
getLogger().warning("Waiting for a Discord request on the main thread!");
|
||||
return RequestBuffer.request(action).get(); // Let the pros handle this
|
||||
}
|
||||
|
||||
/**
|
||||
* Performs Discord actions, retrying when ratelimited.
|
||||
*/
|
||||
public static Void perform(IVoidRequest action) {
|
||||
if (DiscordPlugin.SafeMode)
|
||||
return null;
|
||||
if (Bukkit.isPrimaryThread())
|
||||
throw new RuntimeException("Tried to wait for a Discord request on the main thread. This could cause lag.");
|
||||
return RequestBuffer.request(action).get(); // Let the pros handle this
|
||||
}
|
||||
|
||||
public static void performNoWait(IVoidRequest action) {
|
||||
if (DiscordPlugin.SafeMode)
|
||||
return;
|
||||
RequestBuffer.request(action);
|
||||
}
|
||||
|
||||
public static <T> void performNoWait(IRequest<T> action) {
|
||||
if (DiscordPlugin.SafeMode)
|
||||
return;
|
||||
RequestBuffer.request(action);
|
||||
}
|
||||
|
||||
public static String escape(String message) {
|
||||
return message.replaceAll("([*_~])", Matcher.quoteReplacement("\\")+"$1");
|
||||
}
|
||||
|
||||
public static Logger getLogger() {
|
||||
if (DiscordPlugin.plugin == null || DiscordPlugin.plugin.getLogger() == null)
|
||||
return Logger.getLogger("DiscordPlugin");
|
||||
return DiscordPlugin.plugin.getLogger();
|
||||
}
|
||||
|
||||
public static ConfigData<IChannel> channelData(IHaveConfig config, String key, long defID) {
|
||||
return config.getDataPrimDef(key, defID, id -> DiscordPlugin.dc.getChannelByID((long) id), IIDLinkedObject::getLongID); //We can afford to search for the channel in the cache once (instead of using mainServer)
|
||||
}
|
||||
|
||||
public static ConfigData<IRole> roleData(IHaveConfig config, String key, String defName) {
|
||||
return roleData(config, key, defName, DiscordPlugin.mainServer);
|
||||
}
|
||||
|
||||
public static ConfigData<IRole> roleData(IHaveConfig config, String key, String defName, IGuild guild) {
|
||||
return config.getDataPrimDef(key, defName, name -> {
|
||||
if (!(name instanceof String)) return null;
|
||||
val roles = guild.getRolesByName((String) name);
|
||||
return roles.size() > 0 ? roles.get(0) : null;
|
||||
}, IIDLinkedObject::getLongID);
|
||||
}
|
||||
|
||||
/**
|
||||
* Mentions the <b>bot channel</b>. Useful for help texts.
|
||||
*
|
||||
* @return The string for mentioning the channel
|
||||
*/
|
||||
public static String botmention() {
|
||||
IChannel channel;
|
||||
if (DiscordPlugin.plugin == null
|
||||
|| (channel = DiscordPlugin.plugin.CommandChannel().get()) == null) return "#bot";
|
||||
return channel.mention();
|
||||
}
|
||||
|
||||
/**
|
||||
* Disables the component if one of the given configs return null. Useful for channel/role configs.
|
||||
*
|
||||
* @param component The component to disable if needed
|
||||
* @param configs The configs to check for null
|
||||
* @return Whether the component got disabled and a warning logged
|
||||
*/
|
||||
public static boolean disableIfConfigError(@Nullable Component<DiscordPlugin> component, ConfigData<?>... configs) {
|
||||
for (val config : configs) {
|
||||
if (config.get() == null) {
|
||||
String path = null;
|
||||
try {
|
||||
if (component != null)
|
||||
Component.setComponentEnabled(component, false);
|
||||
val f = ConfigData.class.getDeclaredField("path");
|
||||
f.setAccessible(true); //Hacking my own plugin
|
||||
path = (String) f.get(config);
|
||||
} catch (Exception e) {
|
||||
TBMCCoreAPI.SendException("Failed to disable component after config error!", e);
|
||||
}
|
||||
getLogger().warning("The config value " + path + " isn't set correctly " + (component == null ? "in global settings!" : "for component " + component.getClass().getSimpleName() + "!"));
|
||||
getLogger().warning("Set the correct ID in the config" + (component == null ? "" : " or disable this component") + " to remove this message.");
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
|
@ -1,20 +0,0 @@
|
|||
package buttondevteam.discordplugin;
|
||||
|
||||
import buttondevteam.discordplugin.playerfaker.DiscordFakePlayer;
|
||||
import buttondevteam.discordplugin.playerfaker.VanillaCommandListener;
|
||||
import lombok.Getter;
|
||||
import sx.blah.discord.handle.obj.IChannel;
|
||||
import sx.blah.discord.handle.obj.IUser;
|
||||
|
||||
import java.util.UUID;
|
||||
|
||||
public class DiscordConnectedPlayer extends DiscordFakePlayer implements IMCPlayer<DiscordConnectedPlayer> {
|
||||
private static int nextEntityId = 10000;
|
||||
private @Getter VanillaCommandListener<DiscordConnectedPlayer> vanillaCmdListener;
|
||||
|
||||
public DiscordConnectedPlayer(IUser user, IChannel channel, UUID uuid, String mcname) {
|
||||
super(user, channel, nextEntityId++, uuid, mcname);
|
||||
vanillaCmdListener = new VanillaCommandListener<>(this);
|
||||
}
|
||||
|
||||
}
|
|
@ -1,28 +0,0 @@
|
|||
package buttondevteam.discordplugin;
|
||||
|
||||
import buttondevteam.discordplugin.mcchat.MCChatPrivate;
|
||||
import buttondevteam.lib.player.ChromaGamerBase;
|
||||
import buttondevteam.lib.player.UserClass;
|
||||
|
||||
@UserClass(foldername = "discord")
|
||||
public class DiscordPlayer extends ChromaGamerBase {
|
||||
private String did;
|
||||
// private @Getter @Setter boolean minecraftChatEnabled;
|
||||
|
||||
public DiscordPlayer() {
|
||||
}
|
||||
|
||||
public String getDiscordID() {
|
||||
if (did == null)
|
||||
did = plugindata.getString(getFolder() + "_id");
|
||||
return did;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if player has the private Minecraft chat enabled. For setting the value, see
|
||||
* {@link MCChatPrivate#privateMCChat(sx.blah.discord.handle.obj.IChannel, boolean, sx.blah.discord.handle.obj.IUser, DiscordPlayer)}
|
||||
*/
|
||||
public boolean isMinecraftChatEnabled() {
|
||||
return MCChatPrivate.isMinecraftChatEnabled(this);
|
||||
}
|
||||
}
|
File diff suppressed because it is too large
Load diff
|
@ -1,336 +0,0 @@
|
|||
package buttondevteam.discordplugin;
|
||||
|
||||
import buttondevteam.discordplugin.announcer.AnnouncerModule;
|
||||
import buttondevteam.discordplugin.broadcaster.GeneralEventBroadcasterModule;
|
||||
import buttondevteam.discordplugin.commands.*;
|
||||
import buttondevteam.discordplugin.exceptions.ExceptionListenerModule;
|
||||
import buttondevteam.discordplugin.fun.FunModule;
|
||||
import buttondevteam.discordplugin.listeners.CommonListeners;
|
||||
import buttondevteam.discordplugin.listeners.MCListener;
|
||||
import buttondevteam.discordplugin.mcchat.MCChatPrivate;
|
||||
import buttondevteam.discordplugin.mcchat.MCChatUtils;
|
||||
import buttondevteam.discordplugin.mcchat.MinecraftChatModule;
|
||||
import buttondevteam.discordplugin.mccommands.DiscordMCCommandBase;
|
||||
import buttondevteam.discordplugin.mccommands.ResetMCCommand;
|
||||
import buttondevteam.discordplugin.role.GameRoleModule;
|
||||
import buttondevteam.lib.TBMCCoreAPI;
|
||||
import buttondevteam.lib.architecture.ButtonPlugin;
|
||||
import buttondevteam.lib.architecture.Component;
|
||||
import buttondevteam.lib.architecture.ConfigData;
|
||||
import buttondevteam.lib.chat.TBMCChatAPI;
|
||||
import buttondevteam.lib.player.ChromaGamerBase;
|
||||
import com.google.common.io.Files;
|
||||
import lombok.Getter;
|
||||
import lombok.val;
|
||||
import net.milkbowl.vault.permission.Permission;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.configuration.file.YamlConfiguration;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.plugin.RegisteredServiceProvider;
|
||||
import org.bukkit.scheduler.BukkitTask;
|
||||
import sx.blah.discord.api.ClientBuilder;
|
||||
import sx.blah.discord.api.IDiscordClient;
|
||||
import sx.blah.discord.api.events.IListener;
|
||||
import sx.blah.discord.api.internal.json.objects.EmbedObject;
|
||||
import sx.blah.discord.handle.impl.events.ReadyEvent;
|
||||
import sx.blah.discord.handle.impl.obj.ReactionEmoji;
|
||||
import sx.blah.discord.handle.obj.*;
|
||||
import sx.blah.discord.util.EmbedBuilder;
|
||||
import sx.blah.discord.util.RequestBuffer;
|
||||
|
||||
import java.awt.*;
|
||||
import java.io.File;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.Optional;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.concurrent.TimeoutException;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
public class DiscordPlugin extends ButtonPlugin implements IListener<ReadyEvent> {
|
||||
public static IDiscordClient dc;
|
||||
public static DiscordPlugin plugin;
|
||||
public static boolean SafeMode = true;
|
||||
@Getter
|
||||
private Command2DC manager;
|
||||
|
||||
public ConfigData<Character> Prefix() {
|
||||
return getIConfig().getData("prefix", '/', str -> ((String) str).charAt(0), Object::toString);
|
||||
}
|
||||
|
||||
public static char getPrefix() {
|
||||
if (plugin == null) return '/';
|
||||
return plugin.Prefix().get();
|
||||
}
|
||||
|
||||
public ConfigData<IGuild> MainServer() {
|
||||
return getIConfig().getDataPrimDef("mainServer", 219529124321034241L, id -> dc.getGuildByID((long) id), IIDLinkedObject::getLongID);
|
||||
}
|
||||
|
||||
public ConfigData<IChannel> CommandChannel() {
|
||||
return DPUtils.channelData(getIConfig(), "commandChannel", 239519012529111040L);
|
||||
}
|
||||
|
||||
public ConfigData<IRole> ModRole() {
|
||||
return DPUtils.roleData(getIConfig(), "modRole", "Moderator");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void pluginEnable() {
|
||||
try {
|
||||
getLogger().info("Initializing...");
|
||||
plugin = this;
|
||||
manager = new Command2DC();
|
||||
ClientBuilder cb = new ClientBuilder();
|
||||
File tokenFile = new File("TBMC", "Token.txt");
|
||||
if (tokenFile.exists()) //Legacy support
|
||||
//noinspection UnstableApiUsage
|
||||
cb.withToken(Files.readFirstLine(tokenFile, StandardCharsets.UTF_8));
|
||||
else {
|
||||
File privateFile = new File(getDataFolder(), "private.yml");
|
||||
val conf = YamlConfiguration.loadConfiguration(privateFile);
|
||||
String token = conf.getString("token");
|
||||
if (token == null) {
|
||||
conf.set("token", "Token goes here");
|
||||
conf.save(privateFile);
|
||||
|
||||
getLogger().severe("Token not found! Set it in private.yml");
|
||||
Bukkit.getPluginManager().disablePlugin(this);
|
||||
return;
|
||||
} else
|
||||
cb.withToken(token);
|
||||
}
|
||||
dc = cb.login();
|
||||
dc.getDispatcher().registerListener(this);
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
Bukkit.getPluginManager().disablePlugin(this);
|
||||
}
|
||||
}
|
||||
|
||||
public static IGuild mainServer;
|
||||
|
||||
private static volatile BukkitTask task;
|
||||
private static volatile boolean sent = false;
|
||||
|
||||
@Override
|
||||
public void handle(ReadyEvent event) {
|
||||
try {
|
||||
dc.changePresence(StatusType.DND, ActivityType.PLAYING, "booting");
|
||||
val tries = new AtomicInteger();
|
||||
task = Bukkit.getScheduler().runTaskTimerAsynchronously(this, () -> {
|
||||
tries.incrementAndGet();
|
||||
if (tries.get() > 10) { //5 seconds
|
||||
task.cancel();
|
||||
getLogger().severe("Main server not found! Invite the bot and do /discord reset");
|
||||
//getIConfig().getConfig().set("mainServer", 219529124321034241L); //Needed because it won't save as long as it's null - made it save
|
||||
saveConfig(); //Put default there
|
||||
return;
|
||||
}
|
||||
mainServer = MainServer().get(); //Shouldn't change afterwards
|
||||
if (mainServer == null) {
|
||||
val guilds = dc.getGuilds();
|
||||
if (guilds.size() == 0)
|
||||
return; //If there are no guilds in cache, retry
|
||||
mainServer = guilds.get(0);
|
||||
getLogger().warning("Main server set to first one: " + mainServer.getName());
|
||||
MainServer().set(mainServer); //Save in config
|
||||
}
|
||||
if (!TBMCCoreAPI.IsTestServer()) { //Don't change conditions here, see mainServer=devServer=null in onDisable()
|
||||
dc.changePresence(StatusType.ONLINE, ActivityType.PLAYING, "Minecraft");
|
||||
} else {
|
||||
dc.changePresence(StatusType.ONLINE, ActivityType.PLAYING, "testing");
|
||||
}
|
||||
SafeMode = false;
|
||||
if (task != null)
|
||||
task.cancel();
|
||||
if (!sent) {
|
||||
DPUtils.disableIfConfigError(null, CommandChannel(), ModRole()); //Won't disable, just prints the warning here
|
||||
|
||||
Component.registerComponent(this, new GeneralEventBroadcasterModule());
|
||||
Component.registerComponent(this, new MinecraftChatModule());
|
||||
Component.registerComponent(this, new ExceptionListenerModule());
|
||||
Component.registerComponent(this, new GameRoleModule()); //Needs the mainServer to be set
|
||||
Component.registerComponent(this, new AnnouncerModule());
|
||||
Component.registerComponent(this, new FunModule());
|
||||
new ChromaBot(this).updatePlayerList(); //Initialize ChromaBot - The MCCHatModule is tested to be enabled
|
||||
|
||||
getManager().registerCommand(new VersionCommand());
|
||||
getManager().registerCommand(new UserinfoCommand());
|
||||
getManager().registerCommand(new HelpCommand());
|
||||
getManager().registerCommand(new DebugCommand());
|
||||
getManager().registerCommand(new ConnectCommand());
|
||||
if (ResetMCCommand.resetting) //These will only execute if the chat is enabled
|
||||
ChromaBot.getInstance().sendMessageCustomAsWell("", new EmbedBuilder().withColor(Color.CYAN)
|
||||
.withTitle("Discord plugin restarted - chat connected.").build(), ChannelconBroadcast.RESTART); //Really important to note the chat, hmm
|
||||
else if (getConfig().getBoolean("serverup", false)) {
|
||||
ChromaBot.getInstance().sendMessageCustomAsWell("", new EmbedBuilder().withColor(Color.YELLOW)
|
||||
.withTitle("Server recovered from a crash - chat connected.").build(), ChannelconBroadcast.RESTART);
|
||||
val thr = new Throwable(
|
||||
"The server shut down unexpectedly. See the log of the previous run for more details.");
|
||||
thr.setStackTrace(new StackTraceElement[0]);
|
||||
TBMCCoreAPI.SendException("The server crashed!", thr);
|
||||
} else
|
||||
ChromaBot.getInstance().sendMessageCustomAsWell("", new EmbedBuilder().withColor(Color.GREEN)
|
||||
.withTitle("Server started - chat connected.").build(), ChannelconBroadcast.RESTART);
|
||||
|
||||
ResetMCCommand.resetting = false; //This is the last event handling this flag
|
||||
|
||||
getConfig().set("serverup", true);
|
||||
saveConfig();
|
||||
sent = true;
|
||||
if (TBMCCoreAPI.IsTestServer() && !dc.getOurUser().getName().toLowerCase().contains("test")) {
|
||||
TBMCCoreAPI.SendException(
|
||||
"Won't load because we're in testing mode and not using a separate account.",
|
||||
new Exception(
|
||||
"The plugin refuses to load until you change the token to a testing account. (The account needs to have \"test\" in it's name.)"));
|
||||
Bukkit.getPluginManager().disablePlugin(this);
|
||||
}
|
||||
TBMCCoreAPI.SendUnsentExceptions();
|
||||
TBMCCoreAPI.SendUnsentDebugMessages();
|
||||
}
|
||||
}, 0, 10);
|
||||
for (IListener<?> listener : CommonListeners.getListeners())
|
||||
dc.getDispatcher().registerListener(listener);
|
||||
TBMCCoreAPI.RegisterEventsForExceptions(new MCListener(), this);
|
||||
TBMCChatAPI.AddCommands(this, DiscordMCCommandBase.class);
|
||||
TBMCCoreAPI.RegisterUserClass(DiscordPlayer.class);
|
||||
ChromaGamerBase.addConverter(sender -> Optional.ofNullable(sender instanceof DiscordSenderBase
|
||||
? ((DiscordSenderBase) sender).getChromaUser() : null));
|
||||
setupProviders();
|
||||
} catch (Exception e) {
|
||||
TBMCCoreAPI.SendException("An error occured while enabling DiscordPlugin!", e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Always true, except when running "stop" from console
|
||||
*/
|
||||
public static boolean Restart;
|
||||
|
||||
@Override
|
||||
public void pluginPreDisable() {
|
||||
if (ChromaBot.getInstance() == null) return; //Failed to load
|
||||
EmbedObject embed;
|
||||
if (ResetMCCommand.resetting)
|
||||
embed = new EmbedBuilder().withColor(Color.ORANGE).withTitle("Discord plugin restarting").build();
|
||||
else
|
||||
embed = new EmbedBuilder().withColor(Restart ? Color.ORANGE : Color.RED)
|
||||
.withTitle(Restart ? "Server restarting" : "Server stopping")
|
||||
.withDescription(
|
||||
Bukkit.getOnlinePlayers().size() > 0
|
||||
? (DPUtils
|
||||
.sanitizeString(Bukkit.getOnlinePlayers().stream()
|
||||
.map(Player::getDisplayName).collect(Collectors.joining(", ")))
|
||||
+ (Bukkit.getOnlinePlayers().size() == 1 ? " was " : " were ")
|
||||
+ "kicked the hell out.") //TODO: Make configurable
|
||||
: "") //If 'restart' is disabled then this isn't shown even if joinleave is enabled
|
||||
.build();
|
||||
MCChatUtils.forCustomAndAllMCChat(ch -> {
|
||||
try {
|
||||
DiscordPlugin.sendMessageToChannelWait(ch, "",
|
||||
embed, 5, TimeUnit.SECONDS);
|
||||
} catch (TimeoutException | InterruptedException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}, ChannelconBroadcast.RESTART, false);
|
||||
ChromaBot.getInstance().updatePlayerList();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void pluginDisable() {
|
||||
MCChatPrivate.logoutAll();
|
||||
getConfig().set("serverup", false);
|
||||
if (ChromaBot.getInstance() == null) return; //Failed to load
|
||||
|
||||
saveConfig();
|
||||
try {
|
||||
SafeMode = true; // Stop interacting with Discord
|
||||
ChromaBot.delete();
|
||||
dc.changePresence(StatusType.IDLE, ActivityType.PLAYING, "Chromacraft"); //No longer using the same account for testing
|
||||
dc.logout();
|
||||
//Configs are emptied so channels and servers are fetched again
|
||||
sent = false;
|
||||
} catch (Exception e) {
|
||||
TBMCCoreAPI.SendException("An error occured while disabling DiscordPlugin!", e);
|
||||
}
|
||||
}
|
||||
|
||||
public static final ReactionEmoji DELIVERED_REACTION = ReactionEmoji.of("✅");
|
||||
|
||||
public static void sendMessageToChannel(IChannel channel, String message) {
|
||||
sendMessageToChannel(channel, message, null);
|
||||
}
|
||||
|
||||
public static void sendMessageToChannel(IChannel channel, String message, EmbedObject embed) {
|
||||
try {
|
||||
sendMessageToChannel(channel, message, embed, false);
|
||||
} catch (TimeoutException | InterruptedException e) {
|
||||
e.printStackTrace(); //Shouldn't happen, as we're not waiting on the result
|
||||
}
|
||||
}
|
||||
|
||||
public static IMessage sendMessageToChannelWait(IChannel channel, String message) throws TimeoutException, InterruptedException {
|
||||
return sendMessageToChannelWait(channel, message, null);
|
||||
}
|
||||
|
||||
public static IMessage sendMessageToChannelWait(IChannel channel, String message, EmbedObject embed) throws TimeoutException, InterruptedException {
|
||||
return sendMessageToChannel(channel, message, embed, true);
|
||||
}
|
||||
|
||||
public static IMessage sendMessageToChannelWait(IChannel channel, String message, EmbedObject embed, long timeout, TimeUnit unit) throws TimeoutException, InterruptedException {
|
||||
return sendMessageToChannel(channel, message, embed, true, timeout, unit);
|
||||
}
|
||||
|
||||
private static IMessage sendMessageToChannel(IChannel channel, String message, EmbedObject embed, boolean wait) throws TimeoutException, InterruptedException {
|
||||
return sendMessageToChannel(channel, message, embed, wait, -1, null);
|
||||
}
|
||||
|
||||
private static IMessage sendMessageToChannel(IChannel channel, String message, EmbedObject embed, boolean wait, long timeout, TimeUnit unit) throws TimeoutException, InterruptedException {
|
||||
if (message.length() > 1980) {
|
||||
message = message.substring(0, 1980);
|
||||
DPUtils.getLogger()
|
||||
.warning("Message was too long to send to discord and got truncated. In " + channel.getName());
|
||||
}
|
||||
try {
|
||||
MCChatUtils.resetLastMessage(channel); // If this is a chat message, it'll be set again
|
||||
final String content = message;
|
||||
RequestBuffer.IRequest<IMessage> r = () -> embed == null ? channel.sendMessage(content)
|
||||
: channel.sendMessage(content, embed, false);
|
||||
if (wait) {
|
||||
if (unit != null)
|
||||
return DPUtils.perform(r, timeout, unit);
|
||||
else
|
||||
return DPUtils.perform(r);
|
||||
} else {
|
||||
if (unit != null)
|
||||
plugin.getLogger().warning("Tried to set timeout for non-waiting call.");
|
||||
else
|
||||
DPUtils.performNoWait(r);
|
||||
return null;
|
||||
}
|
||||
} catch (TimeoutException | InterruptedException e) {
|
||||
throw e;
|
||||
} catch (Exception e) {
|
||||
DPUtils.getLogger().warning(
|
||||
"Failed to deliver message to Discord! Channel: " + channel.getName() + " Message: " + message);
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
public static Permission perms;
|
||||
|
||||
public boolean setupProviders() {
|
||||
try {
|
||||
Class.forName("net.milkbowl.vault.permission.Permission");
|
||||
Class.forName("net.milkbowl.vault.chat.Chat");
|
||||
} catch (ClassNotFoundException e) {
|
||||
return false;
|
||||
}
|
||||
|
||||
RegisteredServiceProvider<Permission> permsProvider = Bukkit.getServer().getServicesManager()
|
||||
.getRegistration(Permission.class);
|
||||
perms = permsProvider.getProvider();
|
||||
return perms != null;
|
||||
}
|
||||
}
|
|
@ -1,10 +0,0 @@
|
|||
package buttondevteam.discordplugin;
|
||||
|
||||
import sx.blah.discord.util.DiscordException;
|
||||
import sx.blah.discord.util.MissingPermissionsException;
|
||||
import sx.blah.discord.util.RateLimitException;
|
||||
|
||||
@FunctionalInterface
|
||||
public interface DiscordRunnable {
|
||||
public abstract void run() throws DiscordException, RateLimitException, MissingPermissionsException;
|
||||
}
|
|
@ -1,112 +0,0 @@
|
|||
package buttondevteam.discordplugin;
|
||||
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.Server;
|
||||
import org.bukkit.command.CommandSender;
|
||||
import org.bukkit.permissions.PermissibleBase;
|
||||
import org.bukkit.permissions.Permission;
|
||||
import org.bukkit.permissions.PermissionAttachment;
|
||||
import org.bukkit.permissions.PermissionAttachmentInfo;
|
||||
import org.bukkit.plugin.Plugin;
|
||||
import sx.blah.discord.handle.obj.IChannel;
|
||||
import sx.blah.discord.handle.obj.IUser;
|
||||
|
||||
import java.util.Set;
|
||||
|
||||
public class DiscordSender extends DiscordSenderBase implements CommandSender {
|
||||
private PermissibleBase perm = new PermissibleBase(this);
|
||||
|
||||
private String name;
|
||||
|
||||
public DiscordSender(IUser user, IChannel channel) {
|
||||
super(user, channel);
|
||||
name = user == null ? "Discord user" : user.getDisplayName(DiscordPlugin.mainServer);
|
||||
}
|
||||
|
||||
public DiscordSender(IUser user, IChannel channel, String name) {
|
||||
super(user, channel);
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isPermissionSet(String name) {
|
||||
return perm.isPermissionSet(name);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isPermissionSet(Permission perm) {
|
||||
return this.perm.isPermissionSet(perm);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasPermission(String name) {
|
||||
if (name.contains("essentials") && !name.equals("essentials.list"))
|
||||
return false;
|
||||
return perm.hasPermission(name);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasPermission(Permission perm) {
|
||||
return this.perm.hasPermission(perm);
|
||||
}
|
||||
|
||||
@Override
|
||||
public PermissionAttachment addAttachment(Plugin plugin, String name, boolean value) {
|
||||
return perm.addAttachment(plugin, name, value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public PermissionAttachment addAttachment(Plugin plugin) {
|
||||
return perm.addAttachment(plugin);
|
||||
}
|
||||
|
||||
@Override
|
||||
public PermissionAttachment addAttachment(Plugin plugin, String name, boolean value, int ticks) {
|
||||
return perm.addAttachment(plugin, name, value, ticks);
|
||||
}
|
||||
|
||||
@Override
|
||||
public PermissionAttachment addAttachment(Plugin plugin, int ticks) {
|
||||
return perm.addAttachment(plugin, ticks);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeAttachment(PermissionAttachment attachment) {
|
||||
perm.removeAttachment(attachment);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void recalculatePermissions() {
|
||||
perm.recalculatePermissions();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<PermissionAttachmentInfo> getEffectivePermissions() {
|
||||
return perm.getEffectivePermissions();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isOp() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setOp(boolean value) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public Server getServer() {
|
||||
return Bukkit.getServer();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Spigot spigot() {
|
||||
return new CommandSender.Spigot();
|
||||
}
|
||||
|
||||
}
|
|
@ -1,75 +0,0 @@
|
|||
package buttondevteam.discordplugin;
|
||||
|
||||
import buttondevteam.lib.TBMCCoreAPI;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.command.CommandSender;
|
||||
import org.bukkit.scheduler.BukkitTask;
|
||||
import sx.blah.discord.handle.obj.IChannel;
|
||||
import sx.blah.discord.handle.obj.IUser;
|
||||
|
||||
public abstract class DiscordSenderBase implements CommandSender {
|
||||
/**
|
||||
* May be null.
|
||||
*/
|
||||
protected IUser user;
|
||||
protected IChannel channel;
|
||||
|
||||
protected DiscordSenderBase(IUser user, IChannel channel) {
|
||||
this.user = user;
|
||||
this.channel = channel;
|
||||
}
|
||||
|
||||
private volatile String msgtosend = "";
|
||||
private volatile BukkitTask sendtask;
|
||||
|
||||
/**
|
||||
* Returns the user. May be null.
|
||||
*
|
||||
* @return The user or null.
|
||||
*/
|
||||
public IUser getUser() {
|
||||
return user;
|
||||
}
|
||||
|
||||
public IChannel getChannel() {
|
||||
return channel;
|
||||
}
|
||||
|
||||
private DiscordPlayer chromaUser;
|
||||
|
||||
/**
|
||||
* Loads the user data on first query.
|
||||
*
|
||||
* @return A Chroma user of Discord or a Discord user of Chroma
|
||||
*/
|
||||
public DiscordPlayer getChromaUser() {
|
||||
if (chromaUser == null) chromaUser = DiscordPlayer.getUser(user.getStringID(), DiscordPlayer.class);
|
||||
return chromaUser;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void sendMessage(String message) {
|
||||
try {
|
||||
final boolean broadcast = new Exception().getStackTrace()[2].getMethodName().contains("broadcast");
|
||||
//if (broadcast && DiscordPlugin.hooked) - TODO: What should happen if unhooked
|
||||
if (broadcast)
|
||||
return;
|
||||
final String sendmsg = DPUtils.sanitizeString(message);
|
||||
msgtosend += "\n" + sendmsg;
|
||||
if (sendtask == null)
|
||||
sendtask = Bukkit.getScheduler().runTaskLaterAsynchronously(DiscordPlugin.plugin, () -> {
|
||||
DiscordPlugin.sendMessageToChannel(channel,
|
||||
(!broadcast && user != null ? user.mention() + "\n" : "") + msgtosend.trim());
|
||||
sendtask = null;
|
||||
msgtosend = "";
|
||||
}, 4); // Waits a 0.2 second to gather all/most of the different messages
|
||||
} catch (Exception e) {
|
||||
TBMCCoreAPI.SendException("An error occured while sending message to DiscordSender", e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void sendMessage(String[] messages) {
|
||||
sendMessage(String.join("\n", messages));
|
||||
}
|
||||
}
|
|
@ -1,11 +0,0 @@
|
|||
package buttondevteam.discordplugin;
|
||||
|
||||
import sx.blah.discord.handle.obj.IDiscordObject;
|
||||
import sx.blah.discord.util.DiscordException;
|
||||
import sx.blah.discord.util.MissingPermissionsException;
|
||||
import sx.blah.discord.util.RateLimitException;
|
||||
|
||||
@FunctionalInterface
|
||||
public interface DiscordSupplier<T extends IDiscordObject<T>> {
|
||||
public abstract T get() throws DiscordException, RateLimitException, MissingPermissionsException;
|
||||
}
|
|
@ -1,8 +0,0 @@
|
|||
package buttondevteam.discordplugin;
|
||||
|
||||
import buttondevteam.discordplugin.playerfaker.VanillaCommandListener;
|
||||
import org.bukkit.entity.Player;
|
||||
|
||||
public interface IMCPlayer<T extends DiscordSenderBase & IMCPlayer<T>> extends Player {
|
||||
VanillaCommandListener<T> getVanillaCmdListener();
|
||||
}
|
|
@ -1,142 +0,0 @@
|
|||
package buttondevteam.discordplugin.announcer;
|
||||
|
||||
import buttondevteam.discordplugin.DPUtils;
|
||||
import buttondevteam.discordplugin.DiscordPlayer;
|
||||
import buttondevteam.discordplugin.DiscordPlugin;
|
||||
import buttondevteam.lib.TBMCCoreAPI;
|
||||
import buttondevteam.lib.architecture.Component;
|
||||
import buttondevteam.lib.architecture.ConfigData;
|
||||
import buttondevteam.lib.player.ChromaGamerBase;
|
||||
import com.google.gson.JsonArray;
|
||||
import com.google.gson.JsonElement;
|
||||
import com.google.gson.JsonObject;
|
||||
import com.google.gson.JsonParser;
|
||||
import lombok.val;
|
||||
import org.bukkit.configuration.file.YamlConfiguration;
|
||||
import sx.blah.discord.handle.obj.IChannel;
|
||||
import sx.blah.discord.handle.obj.IMessage;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.List;
|
||||
|
||||
public class AnnouncerModule extends Component<DiscordPlugin> {
|
||||
public ConfigData<IChannel> channel() {
|
||||
return DPUtils.channelData(getConfig(), "channel", 239519012529111040L);
|
||||
}
|
||||
|
||||
public ConfigData<IChannel> modChannel() {
|
||||
return DPUtils.channelData(getConfig(), "modChannel", 239519012529111040L);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set to 0 or >50 to disable
|
||||
*/
|
||||
public ConfigData<Short> keepPinned() {
|
||||
return getConfig().getData("keepPinned", (short) 40);
|
||||
}
|
||||
|
||||
private ConfigData<Long> lastannouncementtime() {
|
||||
return getConfig().getData("lastAnnouncementTime", 0L);
|
||||
}
|
||||
|
||||
private ConfigData<Long> lastseentime() {
|
||||
return getConfig().getData("lastSeenTime", 0L);
|
||||
}
|
||||
|
||||
private static final String SubredditURL = "https://www.reddit.com/r/ChromaGamers";
|
||||
private static boolean stop = false;
|
||||
|
||||
@Override
|
||||
protected void enable() {
|
||||
if (DPUtils.disableIfConfigError(this, channel(), modChannel())) return;
|
||||
stop = false; //If not the first time
|
||||
DPUtils.performNoWait(() -> {
|
||||
try {
|
||||
val keepPinned = keepPinned().get();
|
||||
if (keepPinned == 0) return;
|
||||
val channel = channel().get();
|
||||
List<IMessage> msgs = channel.getPinnedMessages();
|
||||
for (int i = msgs.size() - 1; i >= keepPinned; i--) { // Unpin all pinned messages except the newest 10
|
||||
channel.unpin(msgs.get(i));
|
||||
Thread.sleep(10);
|
||||
}
|
||||
} catch (InterruptedException ignore) {
|
||||
}
|
||||
});
|
||||
val yc = YamlConfiguration.loadConfiguration(new File("plugins/DiscordPlugin", "config.yml")); //Name change
|
||||
if (lastannouncementtime().get() == 0) //Load old data
|
||||
lastannouncementtime().set(yc.getLong("lastannouncementtime"));
|
||||
if (lastseentime().get() == 0)
|
||||
lastseentime().set(yc.getLong("lastseentime"));
|
||||
new Thread(this::AnnouncementGetterThreadMethod).start();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void disable() {
|
||||
stop = true;
|
||||
}
|
||||
|
||||
private void AnnouncementGetterThreadMethod() {
|
||||
while (!stop) {
|
||||
try {
|
||||
if (!isEnabled()) {
|
||||
Thread.sleep(10000);
|
||||
continue;
|
||||
}
|
||||
String body = TBMCCoreAPI.DownloadString(SubredditURL + "/new/.json?limit=10");
|
||||
JsonArray json = new JsonParser().parse(body).getAsJsonObject().get("data").getAsJsonObject()
|
||||
.get("children").getAsJsonArray();
|
||||
StringBuilder msgsb = new StringBuilder();
|
||||
StringBuilder modmsgsb = new StringBuilder();
|
||||
long lastanntime = lastannouncementtime().get();
|
||||
for (int i = json.size() - 1; i >= 0; i--) {
|
||||
JsonObject item = json.get(i).getAsJsonObject();
|
||||
final JsonObject data = item.get("data").getAsJsonObject();
|
||||
String author = data.get("author").getAsString();
|
||||
JsonElement distinguishedjson = data.get("distinguished");
|
||||
String distinguished;
|
||||
if (distinguishedjson.isJsonNull())
|
||||
distinguished = null;
|
||||
else
|
||||
distinguished = distinguishedjson.getAsString();
|
||||
String permalink = "https://www.reddit.com" + data.get("permalink").getAsString();
|
||||
long date = data.get("created_utc").getAsLong();
|
||||
if (date > lastseentime().get())
|
||||
lastseentime().set(date);
|
||||
else if (date > lastannouncementtime().get()) {
|
||||
do {
|
||||
val reddituserclass = ChromaGamerBase.getTypeForFolder("reddit");
|
||||
if (reddituserclass == null)
|
||||
break;
|
||||
val user = ChromaGamerBase.getUser(author, reddituserclass);
|
||||
String id = user.getConnectedID(DiscordPlayer.class);
|
||||
if (id != null)
|
||||
author = "<@" + id + ">";
|
||||
} while (false);
|
||||
if (!author.startsWith("<"))
|
||||
author = "/u/" + author;
|
||||
(distinguished != null && distinguished.equals("moderator") ? modmsgsb : msgsb)
|
||||
.append("A new post was submitted to the subreddit by ").append(author).append("\n")
|
||||
.append(permalink).append("\n");
|
||||
lastanntime = date;
|
||||
}
|
||||
}
|
||||
if (msgsb.length() > 0)
|
||||
channel().get().pin(DiscordPlugin.sendMessageToChannelWait(channel().get(), msgsb.toString()));
|
||||
if (modmsgsb.length() > 0)
|
||||
DiscordPlugin.sendMessageToChannel(modChannel().get(), modmsgsb.toString());
|
||||
if (lastannouncementtime().get() != lastanntime) {
|
||||
lastannouncementtime().set(lastanntime); // If sending succeeded
|
||||
getPlugin().saveConfig(); //TODO: Won't be needed if I implement auto-saving
|
||||
}
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
try {
|
||||
Thread.sleep(10000);
|
||||
} catch (InterruptedException ex) {
|
||||
Thread.currentThread().interrupt();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,35 +0,0 @@
|
|||
package buttondevteam.discordplugin.broadcaster;
|
||||
|
||||
import buttondevteam.discordplugin.DPUtils;
|
||||
import buttondevteam.discordplugin.DiscordPlugin;
|
||||
import buttondevteam.lib.TBMCCoreAPI;
|
||||
import buttondevteam.lib.architecture.Component;
|
||||
import lombok.Getter;
|
||||
|
||||
public class GeneralEventBroadcasterModule extends Component<DiscordPlugin> {
|
||||
private static @Getter boolean hooked = false;
|
||||
|
||||
@Override
|
||||
protected void enable() {
|
||||
try {
|
||||
PlayerListWatcher.hookUp();
|
||||
DPUtils.getLogger().info("Finished hooking into the player list");
|
||||
hooked = true;
|
||||
} catch (Exception e) {
|
||||
TBMCCoreAPI.SendException("Error while hacking the player list!", e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void disable() {
|
||||
try {
|
||||
if (PlayerListWatcher.hookDown())
|
||||
DPUtils.getLogger().info("Finished unhooking the player list!");
|
||||
else
|
||||
DPUtils.getLogger().info("Didn't have the player list hooked.");
|
||||
hooked = false;
|
||||
} catch (Exception e) {
|
||||
TBMCCoreAPI.SendException("Error while hacking the player list!", e);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,362 +0,0 @@
|
|||
package buttondevteam.discordplugin.broadcaster;
|
||||
|
||||
import buttondevteam.discordplugin.mcchat.MCChatUtils;
|
||||
import buttondevteam.lib.TBMCCoreAPI;
|
||||
import com.mojang.authlib.GameProfile;
|
||||
import lombok.val;
|
||||
import net.minecraft.server.v1_12_R1.*;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.Location;
|
||||
import org.bukkit.craftbukkit.v1_12_R1.CraftServer;
|
||||
import org.bukkit.craftbukkit.v1_12_R1.util.CraftChatMessage;
|
||||
import org.bukkit.event.player.PlayerTeleportEvent.TeleportCause;
|
||||
import org.objenesis.ObjenesisStd;
|
||||
|
||||
import java.lang.reflect.Field;
|
||||
import java.lang.reflect.Modifier;
|
||||
import java.util.List;
|
||||
import java.util.UUID;
|
||||
|
||||
public class PlayerListWatcher extends DedicatedPlayerList {
|
||||
private DedicatedPlayerList plist;
|
||||
|
||||
public PlayerListWatcher(DedicatedServer minecraftserver) {
|
||||
super(minecraftserver); // <-- Does some init stuff and calls Bukkit.setServer() so we have to use Objenesis
|
||||
}
|
||||
|
||||
public void sendAll(Packet<?> packet) {
|
||||
plist.sendAll(packet);
|
||||
try { // Some messages get sent by directly constructing a packet
|
||||
if (packet instanceof PacketPlayOutChat) {
|
||||
Field msgf = PacketPlayOutChat.class.getDeclaredField("a");
|
||||
msgf.setAccessible(true);
|
||||
MCChatUtils.forAllMCChat(MCChatUtils.send(((IChatBaseComponent) msgf.get(packet)).toPlainText()));
|
||||
}
|
||||
} catch (Exception e) {
|
||||
TBMCCoreAPI.SendException("Failed to broadcast message sent to all players - hacking failed.", e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void sendMessage(IChatBaseComponent ichatbasecomponent, boolean flag) { // Needed so it calls the overriden method
|
||||
plist.getServer().sendMessage(ichatbasecomponent);
|
||||
ChatMessageType chatmessagetype = flag ? ChatMessageType.SYSTEM : ChatMessageType.CHAT;
|
||||
|
||||
// CraftBukkit start - we run this through our processor first so we can get web links etc
|
||||
this.sendAll(new PacketPlayOutChat(CraftChatMessage.fixComponent(ichatbasecomponent), chatmessagetype));
|
||||
// CraftBukkit end
|
||||
}
|
||||
|
||||
@Override
|
||||
public void sendMessage(IChatBaseComponent ichatbasecomponent) { // Needed so it calls the overriden method
|
||||
this.sendMessage(ichatbasecomponent, true);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void sendMessage(IChatBaseComponent[] iChatBaseComponents) { // Needed so it calls the overridden method
|
||||
for (IChatBaseComponent component : iChatBaseComponents) {
|
||||
sendMessage(component, true);
|
||||
}
|
||||
}
|
||||
|
||||
static void hookUp() throws Exception {
|
||||
Field conf = CraftServer.class.getDeclaredField("console");
|
||||
conf.setAccessible(true);
|
||||
val server = (MinecraftServer) conf.get(Bukkit.getServer());
|
||||
val plw = new ObjenesisStd().newInstance(PlayerListWatcher.class); // Cannot call super constructor
|
||||
plw.plist = (DedicatedPlayerList) server.getPlayerList();
|
||||
plw.maxPlayers = plw.plist.getMaxPlayers();
|
||||
Field plf = plw.getClass().getField("players");
|
||||
plf.setAccessible(true);
|
||||
Field modf = plf.getClass().getDeclaredField("modifiers");
|
||||
modf.setAccessible(true);
|
||||
modf.set(plf, plf.getModifiers() & ~Modifier.FINAL);
|
||||
plf.set(plw, plw.plist.players);
|
||||
server.a(plw);
|
||||
Field pllf = CraftServer.class.getDeclaredField("playerList");
|
||||
pllf.setAccessible(true);
|
||||
pllf.set(Bukkit.getServer(), plw);
|
||||
}
|
||||
|
||||
static boolean hookDown() throws Exception {
|
||||
Field conf = CraftServer.class.getDeclaredField("console");
|
||||
conf.setAccessible(true);
|
||||
val server = (MinecraftServer) conf.get(Bukkit.getServer());
|
||||
val plist = (DedicatedPlayerList) server.getPlayerList();
|
||||
if (!(plist instanceof PlayerListWatcher))
|
||||
return false;
|
||||
server.a(((PlayerListWatcher) plist).plist);
|
||||
Field pllf = CraftServer.class.getDeclaredField("playerList");
|
||||
pllf.setAccessible(true);
|
||||
pllf.set(Bukkit.getServer(), ((PlayerListWatcher) plist).plist);
|
||||
return true;
|
||||
}
|
||||
|
||||
public void a(EntityHuman entityhuman, IChatBaseComponent ichatbasecomponent) {
|
||||
plist.a(entityhuman, ichatbasecomponent);
|
||||
}
|
||||
|
||||
public void a(EntityPlayer entityplayer, int i) {
|
||||
plist.a(entityplayer, i);
|
||||
}
|
||||
|
||||
public void a(EntityPlayer entityplayer, WorldServer worldserver) {
|
||||
plist.a(entityplayer, worldserver);
|
||||
}
|
||||
|
||||
public NBTTagCompound a(EntityPlayer entityplayer) {
|
||||
return plist.a(entityplayer);
|
||||
}
|
||||
|
||||
public void a(int i) {
|
||||
plist.a(i);
|
||||
}
|
||||
|
||||
public void a(NetworkManager networkmanager, EntityPlayer entityplayer) {
|
||||
plist.a(networkmanager, entityplayer);
|
||||
}
|
||||
|
||||
public void a(Packet<?> packet, int i) {
|
||||
plist.a(packet, i);
|
||||
}
|
||||
|
||||
public EntityPlayer a(UUID uuid) {
|
||||
return plist.a(uuid);
|
||||
}
|
||||
|
||||
public void addOp(GameProfile gameprofile) {
|
||||
plist.addOp(gameprofile);
|
||||
}
|
||||
|
||||
public void addWhitelist(GameProfile gameprofile) {
|
||||
plist.addWhitelist(gameprofile);
|
||||
}
|
||||
|
||||
public EntityPlayer attemptLogin(LoginListener loginlistener, GameProfile gameprofile, String hostname) {
|
||||
return plist.attemptLogin(loginlistener, gameprofile, hostname);
|
||||
}
|
||||
|
||||
public String b(boolean flag) {
|
||||
return plist.b(flag);
|
||||
}
|
||||
|
||||
public void b(EntityHuman entityhuman, IChatBaseComponent ichatbasecomponent) {
|
||||
plist.b(entityhuman, ichatbasecomponent);
|
||||
}
|
||||
|
||||
public void b(EntityPlayer entityplayer, WorldServer worldserver) {
|
||||
plist.b(entityplayer, worldserver);
|
||||
}
|
||||
|
||||
public List<EntityPlayer> b(String s) {
|
||||
return plist.b(s);
|
||||
}
|
||||
|
||||
public Location calculateTarget(Location enter, World target) {
|
||||
return plist.calculateTarget(enter, target);
|
||||
}
|
||||
|
||||
public void changeDimension(EntityPlayer entityplayer, int i, TeleportCause cause) {
|
||||
plist.changeDimension(entityplayer, i, cause);
|
||||
}
|
||||
|
||||
public void changeWorld(Entity entity, int i, WorldServer worldserver, WorldServer worldserver1) {
|
||||
plist.changeWorld(entity, i, worldserver, worldserver1);
|
||||
}
|
||||
|
||||
public int d() {
|
||||
return plist.d();
|
||||
}
|
||||
|
||||
public void d(EntityPlayer entityplayer) {
|
||||
plist.d(entityplayer);
|
||||
}
|
||||
|
||||
public String disconnect(EntityPlayer entityplayer) {
|
||||
return plist.disconnect(entityplayer);
|
||||
}
|
||||
|
||||
public boolean equals(Object obj) {
|
||||
return plist.equals(obj);
|
||||
}
|
||||
|
||||
public String[] f() {
|
||||
return plist.f();
|
||||
}
|
||||
|
||||
public void f(EntityPlayer entityplayer) {
|
||||
plist.f(entityplayer);
|
||||
}
|
||||
|
||||
public boolean f(GameProfile gameprofile) {
|
||||
return plist.f(gameprofile);
|
||||
}
|
||||
|
||||
public GameProfile[] g() {
|
||||
return plist.g();
|
||||
}
|
||||
|
||||
public boolean getHasWhitelist() {
|
||||
return plist.getHasWhitelist();
|
||||
}
|
||||
|
||||
public IpBanList getIPBans() {
|
||||
return plist.getIPBans();
|
||||
}
|
||||
|
||||
public int getMaxPlayers() {
|
||||
return plist.getMaxPlayers();
|
||||
}
|
||||
|
||||
public OpList getOPs() {
|
||||
return plist.getOPs();
|
||||
}
|
||||
|
||||
public EntityPlayer getPlayer(String s) {
|
||||
return plist.getPlayer(s);
|
||||
}
|
||||
|
||||
public int getPlayerCount() {
|
||||
return plist.getPlayerCount();
|
||||
}
|
||||
|
||||
public GameProfileBanList getProfileBans() {
|
||||
return plist.getProfileBans();
|
||||
}
|
||||
|
||||
public String[] getSeenPlayers() {
|
||||
return plist.getSeenPlayers();
|
||||
}
|
||||
|
||||
public DedicatedServer getServer() {
|
||||
return plist.getServer();
|
||||
}
|
||||
|
||||
public WhiteList getWhitelist() {
|
||||
return plist.getWhitelist();
|
||||
}
|
||||
|
||||
public String[] getWhitelisted() {
|
||||
return plist.getWhitelisted();
|
||||
}
|
||||
|
||||
public AdvancementDataPlayer h(EntityPlayer entityplayer) {
|
||||
return plist.h(entityplayer);
|
||||
}
|
||||
|
||||
public int hashCode() {
|
||||
return plist.hashCode();
|
||||
}
|
||||
|
||||
public boolean isOp(GameProfile gameprofile) {
|
||||
return plist.isOp(gameprofile);
|
||||
}
|
||||
|
||||
public boolean isWhitelisted(GameProfile gameprofile) {
|
||||
return plist.isWhitelisted(gameprofile);
|
||||
}
|
||||
|
||||
public EntityPlayer moveToWorld(EntityPlayer entityplayer, int i, boolean flag, Location location,
|
||||
boolean avoidSuffocation) {
|
||||
return plist.moveToWorld(entityplayer, i, flag, location, avoidSuffocation);
|
||||
}
|
||||
|
||||
public EntityPlayer moveToWorld(EntityPlayer entityplayer, int i, boolean flag) {
|
||||
return plist.moveToWorld(entityplayer, i, flag);
|
||||
}
|
||||
|
||||
public String[] n() {
|
||||
return plist.n();
|
||||
}
|
||||
|
||||
public void onPlayerJoin(EntityPlayer entityplayer, String joinMessage) {
|
||||
plist.onPlayerJoin(entityplayer, joinMessage);
|
||||
}
|
||||
|
||||
public EntityPlayer processLogin(GameProfile gameprofile, EntityPlayer player) {
|
||||
return plist.processLogin(gameprofile, player);
|
||||
}
|
||||
|
||||
public void reload() {
|
||||
plist.reload();
|
||||
}
|
||||
|
||||
public void reloadWhitelist() {
|
||||
plist.reloadWhitelist();
|
||||
}
|
||||
|
||||
public void removeOp(GameProfile gameprofile) {
|
||||
plist.removeOp(gameprofile);
|
||||
}
|
||||
|
||||
public void removeWhitelist(GameProfile gameprofile) {
|
||||
plist.removeWhitelist(gameprofile);
|
||||
}
|
||||
|
||||
public void repositionEntity(Entity entity, Location exit, boolean portal) {
|
||||
plist.repositionEntity(entity, exit, portal);
|
||||
}
|
||||
|
||||
public int s() {
|
||||
return plist.s();
|
||||
}
|
||||
|
||||
public void savePlayers() {
|
||||
plist.savePlayers();
|
||||
}
|
||||
|
||||
@SuppressWarnings("rawtypes")
|
||||
public void sendAll(Packet packet, EntityHuman entityhuman) {
|
||||
plist.sendAll(packet, entityhuman);
|
||||
}
|
||||
|
||||
@SuppressWarnings("rawtypes")
|
||||
public void sendAll(Packet packet, World world) {
|
||||
plist.sendAll(packet, world);
|
||||
}
|
||||
|
||||
public void sendPacketNearby(EntityHuman entityhuman, double d0, double d1, double d2, double d3, int i,
|
||||
Packet<?> packet) {
|
||||
plist.sendPacketNearby(entityhuman, d0, d1, d2, d3, i, packet);
|
||||
}
|
||||
|
||||
public void sendScoreboard(ScoreboardServer scoreboardserver, EntityPlayer entityplayer) {
|
||||
plist.sendScoreboard(scoreboardserver, entityplayer);
|
||||
}
|
||||
|
||||
public void setHasWhitelist(boolean flag) {
|
||||
plist.setHasWhitelist(flag);
|
||||
}
|
||||
|
||||
public void setPlayerFileData(WorldServer[] aworldserver) {
|
||||
plist.setPlayerFileData(aworldserver);
|
||||
}
|
||||
|
||||
public NBTTagCompound t() {
|
||||
return plist.t();
|
||||
}
|
||||
|
||||
public void tick() {
|
||||
plist.tick();
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
return plist.toString();
|
||||
}
|
||||
|
||||
public void u() {
|
||||
plist.u();
|
||||
}
|
||||
|
||||
public void updateClient(EntityPlayer entityplayer) {
|
||||
plist.updateClient(entityplayer);
|
||||
}
|
||||
|
||||
public List<EntityPlayer> v() {
|
||||
return plist.v();
|
||||
}
|
||||
|
||||
public ServerStatisticManager getStatisticManager(EntityPlayer entityhuman) {
|
||||
return plist.getStatisticManager(entityhuman);
|
||||
}
|
||||
}
|
|
@ -1,17 +0,0 @@
|
|||
package buttondevteam.discordplugin.commands;
|
||||
|
||||
import buttondevteam.discordplugin.DiscordPlugin;
|
||||
import buttondevteam.lib.chat.Command2;
|
||||
|
||||
public class Command2DC extends Command2<ICommand2DC, Command2DCSender> {
|
||||
@Override
|
||||
public void registerCommand(ICommand2DC command) {
|
||||
super.registerCommand(command, DiscordPlugin.getPrefix()); //Needs to be configurable for the helps
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasPermission(Command2DCSender sender, ICommand2DC command) {
|
||||
//return !command.isModOnly() || sender.getMessage().getAuthor().hasRole(DiscordPlugin.plugin.ModRole().get()); //TODO: ModRole may be null; more customisable way?
|
||||
return true;
|
||||
}
|
||||
}
|
|
@ -1,25 +0,0 @@
|
|||
package buttondevteam.discordplugin.commands;
|
||||
|
||||
import buttondevteam.discordplugin.DPUtils;
|
||||
import buttondevteam.lib.chat.Command2Sender;
|
||||
import lombok.Getter;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import sx.blah.discord.handle.obj.IMessage;
|
||||
|
||||
@RequiredArgsConstructor
|
||||
public class Command2DCSender implements Command2Sender {
|
||||
private final @Getter IMessage message;
|
||||
|
||||
@Override
|
||||
public void sendMessage(String message) {
|
||||
if (message.length() == 0) return;
|
||||
message = DPUtils.sanitizeString(message);
|
||||
message = Character.toLowerCase(message.charAt(0)) + message.substring(1);
|
||||
this.message.reply(message);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void sendMessage(String[] message) {
|
||||
sendMessage(String.join("\n", message));
|
||||
}
|
||||
}
|
|
@ -1,62 +0,0 @@
|
|||
package buttondevteam.discordplugin.commands;
|
||||
|
||||
import buttondevteam.discordplugin.DiscordPlayer;
|
||||
import buttondevteam.discordplugin.DiscordPlugin;
|
||||
import buttondevteam.lib.TBMCCoreAPI;
|
||||
import buttondevteam.lib.chat.Command2;
|
||||
import buttondevteam.lib.chat.CommandClass;
|
||||
import buttondevteam.lib.player.TBMCPlayer;
|
||||
import buttondevteam.lib.player.TBMCPlayerBase;
|
||||
import com.google.common.collect.HashBiMap;
|
||||
import lombok.val;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.OfflinePlayer;
|
||||
import org.bukkit.entity.Player;
|
||||
|
||||
@CommandClass(helpText = {
|
||||
"Connect command", //
|
||||
"This command lets you connect your account with a Minecraft account. This allows using the Minecraft chat and other things.", //
|
||||
})
|
||||
public class ConnectCommand extends ICommand2DC {
|
||||
|
||||
/**
|
||||
* Key: Minecraft name<br>
|
||||
* Value: Discord ID
|
||||
*/
|
||||
public static HashBiMap<String, String> WaitingToConnect = HashBiMap.create();
|
||||
|
||||
@Command2.Subcommand
|
||||
public boolean def(Command2DCSender sender, String Minecraftname) {
|
||||
val message = sender.getMessage();
|
||||
if (WaitingToConnect.inverse().containsKey(message.getAuthor().getStringID())) {
|
||||
DiscordPlugin.sendMessageToChannel(message.getChannel(),
|
||||
"Replacing " + WaitingToConnect.inverse().get(message.getAuthor().getStringID()) + " with " + Minecraftname);
|
||||
WaitingToConnect.inverse().remove(message.getAuthor().getStringID());
|
||||
}
|
||||
@SuppressWarnings("deprecation")
|
||||
OfflinePlayer p = Bukkit.getOfflinePlayer(Minecraftname);
|
||||
if (p == null) {
|
||||
DiscordPlugin.sendMessageToChannel(message.getChannel(), "The specified Minecraft player cannot be found");
|
||||
return true;
|
||||
}
|
||||
try (TBMCPlayer pl = TBMCPlayerBase.getPlayer(p.getUniqueId(), TBMCPlayer.class)) {
|
||||
DiscordPlayer dp = pl.getAs(DiscordPlayer.class);
|
||||
if (dp != null && message.getAuthor().getStringID().equals(dp.getDiscordID())) {
|
||||
DiscordPlugin.sendMessageToChannel(message.getChannel(), "You already have this account connected.");
|
||||
return true;
|
||||
}
|
||||
} catch (Exception e) {
|
||||
TBMCCoreAPI.SendException("An error occured while connecting a Discord account!", e);
|
||||
DiscordPlugin.sendMessageToChannel(message.getChannel(), "An internal error occured!\n" + e);
|
||||
}
|
||||
WaitingToConnect.put(p.getName(), message.getAuthor().getStringID());
|
||||
DiscordPlugin.sendMessageToChannel(message.getChannel(),
|
||||
"Alright! Now accept the connection in Minecraft from the account " + Minecraftname
|
||||
+ " before the next server restart. You can also adjust the Minecraft name you want to connect to with the same command.");
|
||||
if (p.isOnline())
|
||||
((Player) p).sendMessage("§bTo connect with the Discord account " + message.getAuthor().getName() + "#"
|
||||
+ message.getAuthor().getDiscriminator() + " do /discord accept");
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
|
@ -1,20 +0,0 @@
|
|||
package buttondevteam.discordplugin.commands;
|
||||
|
||||
import buttondevteam.discordplugin.DiscordPlugin;
|
||||
import buttondevteam.discordplugin.listeners.CommonListeners;
|
||||
import buttondevteam.lib.chat.Command2;
|
||||
import buttondevteam.lib.chat.CommandClass;
|
||||
|
||||
@CommandClass(helpText = {
|
||||
"Switches debug mode."
|
||||
})
|
||||
public class DebugCommand extends ICommand2DC {
|
||||
@Command2.Subcommand
|
||||
public boolean def(Command2DCSender sender, String args) {
|
||||
if (sender.getMessage().getAuthor().hasRole(DiscordPlugin.plugin.ModRole().get()))
|
||||
sender.sendMessage("debug " + (CommonListeners.debug() ? "enabled" : "disabled"));
|
||||
else
|
||||
sender.sendMessage("you need to be a moderator to use this command.");
|
||||
return true;
|
||||
}
|
||||
}
|
|
@ -1,18 +0,0 @@
|
|||
package buttondevteam.discordplugin.commands;
|
||||
|
||||
import buttondevteam.lib.chat.CommandClass;
|
||||
|
||||
@CommandClass(helpText = {
|
||||
"Help command", //
|
||||
"Shows some info about a command or lists the available commands.", //
|
||||
})
|
||||
public class HelpCommand extends ICommand2DC {
|
||||
@Override
|
||||
public boolean def(Command2DCSender sender, String args) {
|
||||
if (args.length() == 0)
|
||||
sender.sendMessage(getManager().getCommandsText());
|
||||
else
|
||||
sender.sendMessage("Soon:tm:"); //TODO
|
||||
return true;
|
||||
}
|
||||
}
|
|
@ -1,20 +0,0 @@
|
|||
package buttondevteam.discordplugin.commands;
|
||||
|
||||
import buttondevteam.discordplugin.DiscordPlugin;
|
||||
import buttondevteam.lib.chat.CommandClass;
|
||||
import buttondevteam.lib.chat.ICommand2;
|
||||
import lombok.Getter;
|
||||
import lombok.val;
|
||||
|
||||
public abstract class ICommand2DC extends ICommand2<Command2DCSender> {
|
||||
public <T extends ICommand2> ICommand2DC() {
|
||||
super(DiscordPlugin.plugin.getManager());
|
||||
val ann = getClass().getAnnotation(CommandClass.class);
|
||||
if (ann == null)
|
||||
modOnly = false;
|
||||
else
|
||||
modOnly = ann.modOnly();
|
||||
}
|
||||
|
||||
private final @Getter boolean modOnly;
|
||||
}
|
|
@ -1,91 +0,0 @@
|
|||
package buttondevteam.discordplugin.commands;
|
||||
|
||||
import buttondevteam.discordplugin.DiscordPlayer;
|
||||
import buttondevteam.discordplugin.DiscordPlugin;
|
||||
import buttondevteam.lib.TBMCCoreAPI;
|
||||
import buttondevteam.lib.chat.Command2;
|
||||
import buttondevteam.lib.chat.CommandClass;
|
||||
import buttondevteam.lib.player.ChromaGamerBase;
|
||||
import buttondevteam.lib.player.ChromaGamerBase.InfoTarget;
|
||||
import lombok.val;
|
||||
import sx.blah.discord.handle.obj.IMessage;
|
||||
import sx.blah.discord.handle.obj.IUser;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
@CommandClass(helpText = {
|
||||
"User information", //
|
||||
"Shows some information about users, from Discord, from Minecraft or from Reddit if they have these accounts connected.", //
|
||||
"If used without args, shows your info.", //
|
||||
})
|
||||
public class UserinfoCommand extends ICommand2DC {
|
||||
@Command2.Subcommand
|
||||
public boolean def(Command2DCSender sender, @Command2.OptionalArg @Command2.TextArg String user) {
|
||||
val message = sender.getMessage();
|
||||
IUser target = null;
|
||||
if (user == null || user.length() == 0)
|
||||
target = message.getAuthor();
|
||||
else {
|
||||
final Optional<IUser> firstmention = message.getMentions().stream()
|
||||
.filter(m -> !m.getStringID().equals(DiscordPlugin.dc.getOurUser().getStringID())).findFirst();
|
||||
if (firstmention.isPresent())
|
||||
target = firstmention.get();
|
||||
else if (user.contains("#")) {
|
||||
String[] targettag = user.split("#");
|
||||
final List<IUser> targets = getUsers(message, targettag[0]);
|
||||
if (targets.size() == 0) {
|
||||
DiscordPlugin.sendMessageToChannel(message.getChannel(),
|
||||
"The user cannot be found (by name): " + user);
|
||||
return true;
|
||||
}
|
||||
for (IUser ptarget : targets) {
|
||||
if (ptarget.getDiscriminator().equalsIgnoreCase(targettag[1])) {
|
||||
target = ptarget;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (target == null) {
|
||||
DiscordPlugin.sendMessageToChannel(message.getChannel(),
|
||||
"The user cannot be found (by discriminator): " + user + "(Found " + targets.size()
|
||||
+ " users with the name.)");
|
||||
return true;
|
||||
}
|
||||
} else {
|
||||
final List<IUser> targets = getUsers(message, user);
|
||||
if (targets.size() == 0) {
|
||||
DiscordPlugin.sendMessageToChannel(message.getChannel(),
|
||||
"The user cannot be found on Discord: " + user);
|
||||
return true;
|
||||
}
|
||||
if (targets.size() > 1) {
|
||||
DiscordPlugin.sendMessageToChannel(message.getChannel(),
|
||||
"Multiple users found with that (nick)name. Please specify the whole tag, like ChromaBot#6338 or use a ping.");
|
||||
return true;
|
||||
}
|
||||
target = targets.get(0);
|
||||
}
|
||||
}
|
||||
try (DiscordPlayer dp = ChromaGamerBase.getUser(target.getStringID(), DiscordPlayer.class)) {
|
||||
StringBuilder uinfo = new StringBuilder("User info for ").append(target.getName()).append(":\n");
|
||||
uinfo.append(dp.getInfo(InfoTarget.Discord));
|
||||
DiscordPlugin.sendMessageToChannel(message.getChannel(), uinfo.toString());
|
||||
} catch (Exception e) {
|
||||
DiscordPlugin.sendMessageToChannel(message.getChannel(), "An error occured while getting the user!");
|
||||
TBMCCoreAPI.SendException("Error while getting info about " + target.getName() + "!", e);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
private List<IUser> getUsers(IMessage message, String args) {
|
||||
final List<IUser> targets;
|
||||
if (message.getChannel().isPrivate())
|
||||
targets = DiscordPlugin.dc.getUsers().stream().filter(u -> u.getName().equalsIgnoreCase(args))
|
||||
.collect(Collectors.toList());
|
||||
else
|
||||
targets = message.getGuild().getUsersByName(args, true);
|
||||
return targets;
|
||||
}
|
||||
|
||||
}
|
|
@ -1,26 +0,0 @@
|
|||
package buttondevteam.discordplugin.commands;
|
||||
|
||||
import buttondevteam.discordplugin.DiscordPlugin;
|
||||
import buttondevteam.lib.chat.Command2;
|
||||
import buttondevteam.lib.chat.CommandClass;
|
||||
import lombok.val;
|
||||
|
||||
@CommandClass(helpText = {
|
||||
"Version",
|
||||
"Returns the plugin's version"
|
||||
})
|
||||
public class VersionCommand extends ICommand2DC {
|
||||
@Command2.Subcommand
|
||||
public boolean def(Command2DCSender sender) {
|
||||
sender.sendMessage(getVersion());
|
||||
return true;
|
||||
}
|
||||
|
||||
public static String[] getVersion() {
|
||||
val desc = DiscordPlugin.plugin.getDescription();
|
||||
return new String[]{ //
|
||||
desc.getFullName(), //
|
||||
desc.getWebsite() //
|
||||
};
|
||||
}
|
||||
}
|
|
@ -1,32 +0,0 @@
|
|||
package buttondevteam.discordplugin.exceptions;
|
||||
|
||||
import buttondevteam.core.ComponentManager;
|
||||
import buttondevteam.discordplugin.DiscordPlugin;
|
||||
import buttondevteam.lib.TBMCDebugMessageEvent;
|
||||
import org.bukkit.event.EventHandler;
|
||||
import org.bukkit.event.Listener;
|
||||
|
||||
public class DebugMessageListener implements Listener{
|
||||
@EventHandler
|
||||
public void onDebugMessage(TBMCDebugMessageEvent e) {
|
||||
SendMessage(e.getDebugMessage());
|
||||
e.setSent();
|
||||
}
|
||||
|
||||
private static void SendMessage(String message) {
|
||||
if (DiscordPlugin.SafeMode || !ComponentManager.isEnabled(ExceptionListenerModule.class))
|
||||
return;
|
||||
try {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
sb.append("```").append("\n");
|
||||
if (message.length() > 2000)
|
||||
message = message.substring(0, 2000);
|
||||
sb.append(message).append("\n");
|
||||
sb.append("```");
|
||||
DiscordPlugin.sendMessageToChannel(ExceptionListenerModule.getChannel(), sb.toString());
|
||||
} catch (Exception ex) {
|
||||
ex.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -1,97 +0,0 @@
|
|||
package buttondevteam.discordplugin.exceptions;
|
||||
|
||||
import buttondevteam.core.ComponentManager;
|
||||
import buttondevteam.discordplugin.DPUtils;
|
||||
import buttondevteam.discordplugin.DiscordPlugin;
|
||||
import buttondevteam.lib.TBMCCoreAPI;
|
||||
import buttondevteam.lib.TBMCExceptionEvent;
|
||||
import buttondevteam.lib.architecture.Component;
|
||||
import buttondevteam.lib.architecture.ConfigData;
|
||||
import org.apache.commons.lang.exception.ExceptionUtils;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.event.EventHandler;
|
||||
import org.bukkit.event.Listener;
|
||||
import sx.blah.discord.handle.obj.IChannel;
|
||||
import sx.blah.discord.handle.obj.IGuild;
|
||||
import sx.blah.discord.handle.obj.IRole;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
public class ExceptionListenerModule extends Component<DiscordPlugin> implements Listener {
|
||||
private List<Throwable> lastthrown = new ArrayList<>();
|
||||
private List<String> lastsourcemsg = new ArrayList<>();
|
||||
|
||||
@EventHandler
|
||||
public void onException(TBMCExceptionEvent e) {
|
||||
if (DiscordPlugin.SafeMode || !ComponentManager.isEnabled(getClass()))
|
||||
return;
|
||||
if (lastthrown.stream()
|
||||
.anyMatch(ex -> Arrays.equals(e.getException().getStackTrace(), ex.getStackTrace())
|
||||
&& (e.getException().getMessage() == null ? ex.getMessage() == null
|
||||
: e.getException().getMessage().equals(ex.getMessage()))) // e.Exception.Message==ex.Message
|
||||
&& lastsourcemsg.contains(e.getSourceMessage()))
|
||||
return;
|
||||
SendException(e.getException(), e.getSourceMessage());
|
||||
if (lastthrown.size() >= 10)
|
||||
lastthrown.remove(0);
|
||||
if (lastsourcemsg.size() >= 10)
|
||||
lastsourcemsg.remove(0);
|
||||
lastthrown.add(e.getException());
|
||||
lastsourcemsg.add(e.getSourceMessage());
|
||||
e.setHandled();
|
||||
}
|
||||
|
||||
private static void SendException(Throwable e, String sourcemessage) {
|
||||
if (instance == null) return;
|
||||
try {
|
||||
IChannel channel = getChannel();
|
||||
assert channel != null;
|
||||
IRole coderRole = instance.pingRole(channel.getGuild()).get();
|
||||
StringBuilder sb = TBMCCoreAPI.IsTestServer() ? new StringBuilder()
|
||||
: new StringBuilder(coderRole == null ? "" : coderRole.mention()).append("\n");
|
||||
sb.append(sourcemessage).append("\n");
|
||||
sb.append("```").append("\n");
|
||||
String stackTrace = Arrays.stream(ExceptionUtils.getStackTrace(e).split("\\n"))
|
||||
.filter(s -> !s.contains("\tat ") || s.contains("\tat buttondevteam."))
|
||||
.collect(Collectors.joining("\n"));
|
||||
if (stackTrace.length() > 1800)
|
||||
stackTrace = stackTrace.substring(0, 1800);
|
||||
sb.append(stackTrace).append("\n");
|
||||
sb.append("```");
|
||||
DiscordPlugin.sendMessageToChannel(channel, sb.toString()); //Instance isn't null here
|
||||
} catch (Exception ex) {
|
||||
ex.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
private static ExceptionListenerModule instance;
|
||||
|
||||
public static IChannel getChannel() {
|
||||
if (instance != null) return instance.channel().get();
|
||||
return null;
|
||||
}
|
||||
|
||||
private ConfigData<IChannel> channel() {
|
||||
return DPUtils.channelData(getConfig(), "channel", 239519012529111040L);
|
||||
}
|
||||
|
||||
private ConfigData<IRole> pingRole(IGuild guild) {
|
||||
return DPUtils.roleData(getConfig(), "pingRole", "Coder", guild);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void enable() {
|
||||
if (DPUtils.disableIfConfigError(this, channel())) return;
|
||||
instance = this;
|
||||
Bukkit.getPluginManager().registerEvents(new ExceptionListenerModule(), getPlugin());
|
||||
TBMCCoreAPI.RegisterEventsForExceptions(new DebugMessageListener(), getPlugin());
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void disable() {
|
||||
instance = null;
|
||||
}
|
||||
}
|
|
@ -1,149 +0,0 @@
|
|||
package buttondevteam.discordplugin.fun;
|
||||
|
||||
import buttondevteam.core.ComponentManager;
|
||||
import buttondevteam.discordplugin.DPUtils;
|
||||
import buttondevteam.discordplugin.DiscordPlugin;
|
||||
import buttondevteam.lib.TBMCCoreAPI;
|
||||
import buttondevteam.lib.architecture.Component;
|
||||
import buttondevteam.lib.architecture.ConfigData;
|
||||
import com.google.common.collect.Lists;
|
||||
import lombok.val;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.event.EventHandler;
|
||||
import org.bukkit.event.Listener;
|
||||
import org.bukkit.event.player.PlayerJoinEvent;
|
||||
import sx.blah.discord.handle.impl.events.user.PresenceUpdateEvent;
|
||||
import sx.blah.discord.handle.obj.*;
|
||||
import sx.blah.discord.util.EmbedBuilder;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Calendar;
|
||||
import java.util.Random;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.stream.IntStream;
|
||||
|
||||
public class FunModule extends Component<DiscordPlugin> implements Listener {
|
||||
private static final String[] serverReadyStrings = new String[]{"In one week from now", // Ali
|
||||
"Between now and the heat-death of the universe.", // Ghostise
|
||||
"Soonâ„¢", "Ask again this time next month", // Ghostise
|
||||
"In about 3 seconds", // Nicolai
|
||||
"After we finish 8 plugins", // Ali
|
||||
"Tomorrow.", // Ali
|
||||
"After one tiiiny feature", // Ali
|
||||
"Next commit", // Ali
|
||||
"After we finish strangling Towny", // Ali
|
||||
"When we kill every *fucking* bug", // Ali
|
||||
"Once the server stops screaming.", // Ali
|
||||
"After HL3 comes out", // Ali
|
||||
"Next time you ask", // Ali
|
||||
"When will *you* be open?" // Ali
|
||||
};
|
||||
|
||||
private ConfigData<Boolean> serverReady() {
|
||||
return getConfig().getData("serverReady", true);
|
||||
}
|
||||
|
||||
private ConfigData<ArrayList<String>> serverReadyAnswers() {
|
||||
return getConfig().getData("serverReadyAnswers", () -> Lists.newArrayList(serverReadyStrings)); //TODO: Test
|
||||
}
|
||||
|
||||
private static final String[] serverReadyQuestions = new String[]{"when will the server be open",
|
||||
"when will the server be ready", "when will the server be done", "when will the server be complete",
|
||||
"when will the server be finished", "when's the server ready", "when's the server open",
|
||||
"Vhen vill ze server be open?"};
|
||||
|
||||
private static final Random serverReadyRandom = new Random();
|
||||
private static final ArrayList<Short> usableServerReadyStrings = new ArrayList<>(0);
|
||||
|
||||
private void createUsableServerReadyStrings() {
|
||||
IntStream.range(0, serverReadyAnswers().get().size())
|
||||
.forEach(i -> FunModule.usableServerReadyStrings.add((short) i));
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void enable() {
|
||||
registerListener(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void disable() {
|
||||
lastlist = lastlistp = ListC = 0;
|
||||
}
|
||||
|
||||
private static short lastlist = 0;
|
||||
private static short lastlistp = 0;
|
||||
|
||||
private static short ListC = 0;
|
||||
|
||||
public static boolean executeMemes(IMessage message) {
|
||||
val fm = ComponentManager.getIfEnabled(FunModule.class);
|
||||
if (fm == null) return false;
|
||||
String msglowercased = message.getContent().toLowerCase();
|
||||
lastlist++;
|
||||
if (lastlist > 5) {
|
||||
ListC = 0;
|
||||
lastlist = 0;
|
||||
}
|
||||
if (msglowercased.equals("list") && Bukkit.getOnlinePlayers().size() == lastlistp && ListC++ > 2) // Lowered already
|
||||
{
|
||||
message.reply("Stop it. You know the answer.");
|
||||
lastlist = 0;
|
||||
lastlistp = (short) Bukkit.getOnlinePlayers().size();
|
||||
return true; //Handled
|
||||
}
|
||||
lastlistp = (short) Bukkit.getOnlinePlayers().size(); //Didn't handle
|
||||
if (fm.serverReady().get()) {
|
||||
if (!TBMCCoreAPI.IsTestServer()
|
||||
&& Arrays.stream(serverReadyQuestions).anyMatch(msglowercased::contains)) {
|
||||
int next;
|
||||
if (usableServerReadyStrings.size() == 0)
|
||||
fm.createUsableServerReadyStrings();
|
||||
next = usableServerReadyStrings.remove(serverReadyRandom.nextInt(usableServerReadyStrings.size()));
|
||||
DiscordPlugin.sendMessageToChannel(message.getChannel(), serverReadyStrings[next]);
|
||||
return false; //Still process it as a command/mcchat if needed
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@EventHandler
|
||||
public void onPlayerJoin(PlayerJoinEvent event) {
|
||||
ListC = 0;
|
||||
}
|
||||
|
||||
private ConfigData<IRole> fullHouseDevRole(IGuild guild) {
|
||||
return DPUtils.roleData(getConfig(), "fullHouseDevRole", "Developer", guild);
|
||||
}
|
||||
|
||||
|
||||
private ConfigData<IChannel> fullHouseChannel() {
|
||||
return DPUtils.channelData(getConfig(), "fullHouseChannel", 219626707458457603L);
|
||||
}
|
||||
|
||||
private static long lasttime = 0;
|
||||
|
||||
public static void handleFullHouse(PresenceUpdateEvent event) {
|
||||
val fm = ComponentManager.getIfEnabled(FunModule.class);
|
||||
if (fm == null) return;
|
||||
val channel = fm.fullHouseChannel().get();
|
||||
if (channel == null) return;
|
||||
val devrole = fm.fullHouseDevRole(channel.getGuild()).get();
|
||||
if (devrole == null) return;
|
||||
if (event.getOldPresence().getStatus().equals(StatusType.OFFLINE)
|
||||
&& !event.getNewPresence().getStatus().equals(StatusType.OFFLINE)
|
||||
&& event.getUser().getRolesForGuild(channel.getGuild()).stream()
|
||||
.anyMatch(r -> r.getLongID() == devrole.getLongID())
|
||||
&& channel.getGuild().getUsersByRole(devrole).stream()
|
||||
.noneMatch(u -> u.getPresence().getStatus().equals(StatusType.OFFLINE))
|
||||
&& lasttime + 10 < TimeUnit.NANOSECONDS.toHours(System.nanoTime())
|
||||
&& Calendar.getInstance().get(Calendar.DAY_OF_MONTH) % 5 == 0) {
|
||||
DiscordPlugin.sendMessageToChannel(channel, "Full house!",
|
||||
new EmbedBuilder()
|
||||
.withImage(
|
||||
"https://cdn.discordapp.com/attachments/249295547263877121/249687682618359808/poker-hand-full-house-aces-kings-playing-cards-15553791.png")
|
||||
.build());
|
||||
lasttime = TimeUnit.NANOSECONDS.toHours(System.nanoTime());
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,73 +0,0 @@
|
|||
package buttondevteam.discordplugin.listeners;
|
||||
|
||||
import buttondevteam.discordplugin.DiscordPlugin;
|
||||
import buttondevteam.discordplugin.commands.Command2DCSender;
|
||||
import buttondevteam.lib.TBMCCoreAPI;
|
||||
import sx.blah.discord.handle.obj.IChannel;
|
||||
import sx.blah.discord.handle.obj.IMessage;
|
||||
import sx.blah.discord.handle.obj.IRole;
|
||||
|
||||
public class CommandListener {
|
||||
/**
|
||||
* Runs a ChromaBot command. If mentionedonly is false, it will only execute the command if it was in #bot with the correct prefix or in private.
|
||||
*
|
||||
* @param message The Discord message
|
||||
* @param mentionedonly Only run the command if ChromaBot is mentioned at the start of the message
|
||||
* @return Whether it ran the command
|
||||
*/
|
||||
public static boolean runCommand(IMessage message, boolean mentionedonly) {
|
||||
if (message.getContent().length() == 0)
|
||||
return false; //Pin messages and such, let the mcchat listener deal with it
|
||||
final IChannel channel = message.getChannel();
|
||||
if (!mentionedonly) { //mentionedonly conditions are in CommonListeners
|
||||
if (!message.getChannel().isPrivate()
|
||||
&& !(message.getContent().charAt(0) == DiscordPlugin.getPrefix()
|
||||
&& channel.getStringID().equals(DiscordPlugin.plugin.CommandChannel().get().getStringID()))) //
|
||||
return false;
|
||||
message.getChannel().setTypingStatus(true); // Fun
|
||||
}
|
||||
final StringBuilder cmdwithargs = new StringBuilder(message.getContent());
|
||||
final String mention = DiscordPlugin.dc.getOurUser().mention(false);
|
||||
final String mentionNick = DiscordPlugin.dc.getOurUser().mention(true);
|
||||
boolean gotmention = checkanddeletemention(cmdwithargs, mention, message);
|
||||
gotmention = checkanddeletemention(cmdwithargs, mentionNick, message) || gotmention;
|
||||
for (String mentionRole : (Iterable<String>) message.getRoleMentions().stream().filter(r -> DiscordPlugin.dc.getOurUser().hasRole(r)).map(IRole::mention)::iterator)
|
||||
gotmention = checkanddeletemention(cmdwithargs, mentionRole, message) || gotmention; // Delete all mentions
|
||||
if (mentionedonly && !gotmention) {
|
||||
message.getChannel().setTypingStatus(false);
|
||||
return false;
|
||||
}
|
||||
message.getChannel().setTypingStatus(true);
|
||||
String cmdwithargsString = cmdwithargs.toString();
|
||||
try {
|
||||
if (!DiscordPlugin.plugin.getManager().handleCommand(new Command2DCSender(message), cmdwithargsString))
|
||||
message.reply("Unknown command. Do " + DiscordPlugin.getPrefix() + "help for help.\n" + cmdwithargsString);
|
||||
} catch (Exception e) {
|
||||
TBMCCoreAPI.SendException("Failed to process Discord command: " + cmdwithargsString, e);
|
||||
}
|
||||
message.getChannel().setTypingStatus(false);
|
||||
return true;
|
||||
}
|
||||
|
||||
private static boolean checkanddeletemention(StringBuilder cmdwithargs, String mention, IMessage message) {
|
||||
if (message.getContent().startsWith(mention)) // TODO: Resolve mentions: Compound arguments, either a mention or text
|
||||
if (cmdwithargs.length() > mention.length() + 1) {
|
||||
int i = cmdwithargs.indexOf(" ", mention.length());
|
||||
if (i == -1)
|
||||
i = mention.length();
|
||||
else
|
||||
//noinspection StatementWithEmptyBody
|
||||
for (; i < cmdwithargs.length() && cmdwithargs.charAt(i) == ' '; i++)
|
||||
; //Removes any space before the command
|
||||
cmdwithargs.delete(0, i);
|
||||
cmdwithargs.insert(0, DiscordPlugin.getPrefix()); //Always use the prefix for processing
|
||||
} else
|
||||
cmdwithargs.replace(0, cmdwithargs.length(), DiscordPlugin.getPrefix() + "help");
|
||||
else {
|
||||
return false; //Don't treat / as mention, mentions can be used in public mcchat
|
||||
}
|
||||
if (cmdwithargs.length() == 0)
|
||||
cmdwithargs.replace(0, cmdwithargs.length(), DiscordPlugin.getPrefix() + "help");
|
||||
return true;
|
||||
}
|
||||
}
|
|
@ -1,77 +0,0 @@
|
|||
package buttondevteam.discordplugin.listeners;
|
||||
|
||||
import buttondevteam.discordplugin.DPUtils;
|
||||
import buttondevteam.discordplugin.DiscordPlugin;
|
||||
import buttondevteam.discordplugin.fun.FunModule;
|
||||
import buttondevteam.discordplugin.mcchat.MinecraftChatModule;
|
||||
import buttondevteam.discordplugin.role.GameRoleModule;
|
||||
import buttondevteam.lib.TBMCCoreAPI;
|
||||
import buttondevteam.lib.architecture.Component;
|
||||
import lombok.val;
|
||||
import sx.blah.discord.api.events.IListener;
|
||||
import sx.blah.discord.handle.impl.events.guild.channel.message.MessageReceivedEvent;
|
||||
import sx.blah.discord.handle.impl.events.guild.role.RoleCreateEvent;
|
||||
import sx.blah.discord.handle.impl.events.guild.role.RoleDeleteEvent;
|
||||
import sx.blah.discord.handle.impl.events.guild.role.RoleUpdateEvent;
|
||||
import sx.blah.discord.handle.impl.events.user.PresenceUpdateEvent;
|
||||
|
||||
public class CommonListeners {
|
||||
|
||||
/*
|
||||
MentionEvent:
|
||||
- CommandListener (starts with mention, only 'channelcon' and not in #bot)
|
||||
|
||||
MessageReceivedEvent:
|
||||
- v CommandListener (starts with mention, in #bot or a connected chat)
|
||||
- Minecraft chat (is enabled in the channel and message isn't [/]mcchat)
|
||||
- CommandListener (with the correct prefix in #bot, or in private)
|
||||
*/
|
||||
public static IListener<?>[] getListeners() {
|
||||
return new IListener[]{new IListener<MessageReceivedEvent>() {
|
||||
@Override
|
||||
public void handle(MessageReceivedEvent event) {
|
||||
if (DiscordPlugin.SafeMode)
|
||||
return;
|
||||
if (event.getMessage().getAuthor().isBot())
|
||||
return;
|
||||
if (FunModule.executeMemes(event.getMessage()))
|
||||
return;
|
||||
try {
|
||||
boolean handled = false;
|
||||
val commandChannel = DiscordPlugin.plugin.CommandChannel().get();
|
||||
if ((commandChannel != null && event.getChannel().getLongID() == commandChannel.getLongID()) //If mentioned, that's higher than chat
|
||||
|| event.getMessage().getContent().contains("channelcon")) //Only 'channelcon' is allowed in other channels
|
||||
handled = CommandListener.runCommand(event.getMessage(), true); //#bot is handled here
|
||||
if (handled) return;
|
||||
val mcchat = Component.getComponents().get(MinecraftChatModule.class);
|
||||
if (mcchat != null && mcchat.isEnabled()) //ComponentManager.isEnabled() searches the component again
|
||||
handled = ((MinecraftChatModule) mcchat).getListener().handleDiscord(event); //Also runs Discord commands in chat channels
|
||||
if (!handled)
|
||||
handled = CommandListener.runCommand(event.getMessage(), false);
|
||||
} catch (Exception e) {
|
||||
TBMCCoreAPI.SendException("An error occured while handling a message!", e);
|
||||
}
|
||||
}
|
||||
}, new IListener<sx.blah.discord.handle.impl.events.user.PresenceUpdateEvent>() {
|
||||
@Override
|
||||
public void handle(PresenceUpdateEvent event) {
|
||||
if (DiscordPlugin.SafeMode)
|
||||
return;
|
||||
FunModule.handleFullHouse(event);
|
||||
}
|
||||
}, (IListener<RoleCreateEvent>) GameRoleModule::handleRoleEvent, //
|
||||
(IListener<RoleDeleteEvent>) GameRoleModule::handleRoleEvent, //
|
||||
(IListener<RoleUpdateEvent>) GameRoleModule::handleRoleEvent};
|
||||
}
|
||||
|
||||
private static boolean debug = false;
|
||||
|
||||
public static void debug(String debug) {
|
||||
if (CommonListeners.debug) //Debug
|
||||
DPUtils.getLogger().info(debug);
|
||||
}
|
||||
|
||||
public static boolean debug() {
|
||||
return debug = !debug;
|
||||
}
|
||||
}
|
|
@ -1,4 +0,0 @@
|
|||
package buttondevteam.discordplugin.listeners;
|
||||
|
||||
public interface DiscordListener {
|
||||
}
|
|
@ -1,43 +0,0 @@
|
|||
package buttondevteam.discordplugin.listeners;
|
||||
|
||||
import buttondevteam.discordplugin.DiscordPlayer;
|
||||
import buttondevteam.discordplugin.DiscordPlugin;
|
||||
import buttondevteam.discordplugin.commands.ConnectCommand;
|
||||
import buttondevteam.lib.player.TBMCPlayerGetInfoEvent;
|
||||
import buttondevteam.lib.player.TBMCPlayerJoinEvent;
|
||||
import org.bukkit.event.EventHandler;
|
||||
import org.bukkit.event.Listener;
|
||||
import org.bukkit.event.server.ServerCommandEvent;
|
||||
import sx.blah.discord.handle.obj.IUser;
|
||||
|
||||
public class MCListener implements Listener {
|
||||
@EventHandler
|
||||
public void onPlayerJoin(TBMCPlayerJoinEvent e) {
|
||||
if (ConnectCommand.WaitingToConnect.containsKey(e.GetPlayer().PlayerName().get())) {
|
||||
@SuppressWarnings("ConstantConditions") IUser user = DiscordPlugin.dc
|
||||
.getUserByID(Long.parseLong(ConnectCommand.WaitingToConnect.get(e.GetPlayer().PlayerName().get())));
|
||||
e.getPlayer().sendMessage("§bTo connect with the Discord account @" + user.getName() + "#" + user.getDiscriminator()
|
||||
+ " do /discord accept");
|
||||
e.getPlayer().sendMessage("§bIf it wasn't you, do /discord decline");
|
||||
}
|
||||
}
|
||||
|
||||
@EventHandler
|
||||
public void onGetInfo(TBMCPlayerGetInfoEvent e) {
|
||||
if (DiscordPlugin.SafeMode)
|
||||
return;
|
||||
DiscordPlayer dp = e.getPlayer().getAs(DiscordPlayer.class);
|
||||
if (dp == null || dp.getDiscordID() == null || dp.getDiscordID().equals(""))
|
||||
return;
|
||||
IUser user = DiscordPlugin.dc.getUserByID(Long.parseLong(dp.getDiscordID()));
|
||||
e.addInfo("Discord tag: " + user.getName() + "#" + user.getDiscriminator());
|
||||
e.addInfo(user.getPresence().getStatus().toString());
|
||||
if (user.getPresence().getActivity().isPresent() && user.getPresence().getText().isPresent())
|
||||
e.addInfo(user.getPresence().getActivity().get() + ": " + user.getPresence().getText().get());
|
||||
}
|
||||
|
||||
@EventHandler
|
||||
public void onServerCommand(ServerCommandEvent e) {
|
||||
DiscordPlugin.Restart = !e.getCommand().equalsIgnoreCase("stop"); // The variable is always true except if stopped
|
||||
}
|
||||
}
|
|
@ -1,150 +0,0 @@
|
|||
package buttondevteam.discordplugin.mcchat;
|
||||
|
||||
import buttondevteam.core.component.channel.Channel;
|
||||
import buttondevteam.core.component.channel.ChatRoom;
|
||||
import buttondevteam.discordplugin.*;
|
||||
import buttondevteam.discordplugin.commands.Command2DCSender;
|
||||
import buttondevteam.discordplugin.commands.ICommand2DC;
|
||||
import buttondevteam.lib.TBMCSystemChatEvent;
|
||||
import buttondevteam.lib.chat.Command2;
|
||||
import buttondevteam.lib.chat.CommandClass;
|
||||
import buttondevteam.lib.player.TBMCPlayer;
|
||||
import lombok.val;
|
||||
import org.bukkit.Bukkit;
|
||||
import sx.blah.discord.handle.obj.IMessage;
|
||||
import sx.blah.discord.handle.obj.Permissions;
|
||||
import sx.blah.discord.util.PermissionUtils;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.Arrays;
|
||||
import java.util.HashSet;
|
||||
import java.util.function.Supplier;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
@CommandClass(helpText = {"Channel connect", //
|
||||
"This command allows you to connect a Minecraft channel to a Discord channel (just like how the global chat is connected to #minecraft-chat).", //
|
||||
"You need to have access to the MC channel and have manage permissions on the Discord channel.", //
|
||||
"You also need to have your Minecraft account connected. In #bot use /connect <mcname>.", //
|
||||
"Call this command from the channel you want to use.", //
|
||||
"Usage: @Bot channelcon <mcchannel>", //
|
||||
"Use the ID (command) of the channel, for example `g` for the global chat.", //
|
||||
"To remove a connection use @ChromaBot channelcon remove in the channel.", //
|
||||
"Mentioning the bot is needed in this case because the / prefix only works in #bot.", //
|
||||
"Invite link: <https://discordapp.com/oauth2/authorize?client_id=226443037893591041&scope=bot&permissions=268509264>" //
|
||||
})
|
||||
public class ChannelconCommand extends ICommand2DC {
|
||||
@Command2.Subcommand
|
||||
public boolean remove(Command2DCSender sender) {
|
||||
val message = sender.getMessage();
|
||||
if (checkPerms(message)) return true;
|
||||
if (MCChatCustom.removeCustomChat(message.getChannel()))
|
||||
message.reply("channel connection removed.");
|
||||
else
|
||||
message.reply("this channel isn't connected.");
|
||||
return true;
|
||||
}
|
||||
|
||||
@Command2.Subcommand
|
||||
public boolean toggle(Command2DCSender sender, @Command2.OptionalArg String toggle) {
|
||||
val message = sender.getMessage();
|
||||
if (checkPerms(message)) return true;
|
||||
val cc = MCChatCustom.getCustomChat(message.getChannel());
|
||||
if (cc == null)
|
||||
return respond(sender, "this channel isn't connected.");
|
||||
Supplier<String> togglesString = () -> Arrays.stream(ChannelconBroadcast.values()).map(t -> t.toString().toLowerCase() + ": " + ((cc.toggles & t.flag) == 0 ? "disabled" : "enabled")).collect(Collectors.joining("\n"))
|
||||
+ "\n\n" + TBMCSystemChatEvent.BroadcastTarget.stream().map(target -> target.getName() + ": " + (cc.brtoggles.contains(target) ? "enabled" : "disabled")).collect(Collectors.joining("\n"));
|
||||
if (toggle == null) {
|
||||
message.reply("toggles:\n" + togglesString.get());
|
||||
return true;
|
||||
}
|
||||
String arg = toggle.toUpperCase();
|
||||
val b = Arrays.stream(ChannelconBroadcast.values()).filter(t -> t.toString().equals(arg)).findAny();
|
||||
if (!b.isPresent()) {
|
||||
val bt = TBMCSystemChatEvent.BroadcastTarget.get(arg);
|
||||
if (bt == null) {
|
||||
message.reply("cannot find toggle. Toggles:\n" + togglesString.get());
|
||||
return true;
|
||||
}
|
||||
final boolean add;
|
||||
if (add = !cc.brtoggles.contains(bt))
|
||||
cc.brtoggles.add(bt);
|
||||
else
|
||||
cc.brtoggles.remove(bt);
|
||||
return respond(sender, "'" + bt.getName() + "' " + (add ? "en" : "dis") + "abled");
|
||||
}
|
||||
//A B | F
|
||||
//------- A: original - B: mask - F: new
|
||||
//0 0 | 0
|
||||
//0 1 | 1
|
||||
//1 0 | 1
|
||||
//1 1 | 0
|
||||
// XOR
|
||||
cc.toggles ^= b.get().flag;
|
||||
message.reply("'" + b.get().toString().toLowerCase() + "' " + ((cc.toggles & b.get().flag) == 0 ? "disabled" : "enabled"));
|
||||
return true;
|
||||
}
|
||||
|
||||
@Command2.Subcommand
|
||||
public boolean def(Command2DCSender sender, String channelID) {
|
||||
val message = sender.getMessage();
|
||||
if (checkPerms(message)) return true;
|
||||
if (MCChatCustom.hasCustomChat(message.getChannel()))
|
||||
return respond(sender, "this channel is already connected to a Minecraft channel. Use `@ChromaBot channelcon remove` to remove it.");
|
||||
val chan = Channel.getChannels().filter(ch -> ch.ID.equalsIgnoreCase(channelID) || (Arrays.stream(ch.IDs().get()).anyMatch(cid -> cid.equalsIgnoreCase(channelID)))).findAny();
|
||||
if (!chan.isPresent()) { //TODO: Red embed that disappears over time (kinda like the highlight messages in OW)
|
||||
message.reply("MC channel with ID '" + channelID + "' not found! The ID is the command for it without the /.");
|
||||
return true;
|
||||
}
|
||||
val dp = DiscordPlayer.getUser(message.getAuthor().getStringID(), DiscordPlayer.class);
|
||||
val chp = dp.getAs(TBMCPlayer.class);
|
||||
if (chp == null) {
|
||||
message.reply("you need to connect your Minecraft account. On our server in " + DPUtils.botmention() + " do " + DiscordPlugin.getPrefix() + "connect <MCname>");
|
||||
return true;
|
||||
}
|
||||
DiscordConnectedPlayer dcp = new DiscordConnectedPlayer(message.getAuthor(), message.getChannel(), chp.getUUID(), Bukkit.getOfflinePlayer(chp.getUUID()).getName());
|
||||
//Using a fake player with no login/logout, should be fine for this event
|
||||
String groupid = chan.get().getGroupID(dcp);
|
||||
if (groupid == null && !(chan.get() instanceof ChatRoom)) { //ChatRooms don't allow it unless the user joins, which happens later
|
||||
message.reply("sorry, you cannot use that Minecraft channel.");
|
||||
return true;
|
||||
}
|
||||
if (chan.get() instanceof ChatRoom) { //ChatRooms don't work well
|
||||
message.reply("chat rooms are not supported yet.");
|
||||
return true;
|
||||
}
|
||||
/*if (MCChatListener.getCustomChats().stream().anyMatch(cc -> cc.groupID.equals(groupid) && cc.mcchannel.ID.equals(chan.get().ID))) {
|
||||
message.reply("sorry, this MC chat is already connected to a different channel, multiple channels are not supported atm.");
|
||||
return true;
|
||||
}*/ //TODO: "Channel admins" that can connect channels?
|
||||
MCChatCustom.addCustomChat(message.getChannel(), groupid, chan.get(), message.getAuthor(), dcp, 0, new HashSet<>());
|
||||
if (chan.get() instanceof ChatRoom)
|
||||
message.reply("alright, connection made to the room!");
|
||||
else
|
||||
message.reply("alright, connection made to group `" + groupid + "`!");
|
||||
return true;
|
||||
}
|
||||
|
||||
private boolean checkPerms(IMessage message) {
|
||||
if (!PermissionUtils.hasPermissions(message.getChannel(), message.getAuthor(), Permissions.MANAGE_CHANNEL)) {
|
||||
message.reply("you need to have manage permissions for this channel!");
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String[] getHelpText(Method method, Command2.Subcommand ann) {
|
||||
return new String[]{ //
|
||||
"Channel connect", //
|
||||
"This command allows you to connect a Minecraft channel to a Discord channel (just like how the global chat is connected to #minecraft-chat).", //
|
||||
"You need to have access to the MC channel and have manage permissions on the Discord channel.", //
|
||||
"You also need to have your Minecraft account connected. In " + DPUtils.botmention() + " use " + DiscordPlugin.getPrefix() + "connect <mcname>.", //
|
||||
"Call this command from the channel you want to use.", //
|
||||
"Usage: @" + DiscordPlugin.dc.getOurUser().getName() + " channelcon <mcchannel>", //
|
||||
"Use the ID (command) of the channel, for example `g` for the global chat.", //
|
||||
"To remove a connection use @ChromaBot channelcon remove in the channel.", //
|
||||
"Mentioning the bot is needed in this case because the " + DiscordPlugin.getPrefix() + " prefix only works in " + DPUtils.botmention() + ".", //
|
||||
"Invite link: <https://discordapp.com/oauth2/authorize?client_id=226443037893591041&scope=bot&permissions=268509264>" // TODO: Set correct client ID
|
||||
};
|
||||
}
|
||||
}
|
|
@ -1,39 +0,0 @@
|
|||
package buttondevteam.discordplugin.mcchat;
|
||||
|
||||
import buttondevteam.discordplugin.DiscordPlayer;
|
||||
import buttondevteam.discordplugin.DiscordPlugin;
|
||||
import buttondevteam.discordplugin.commands.Command2DCSender;
|
||||
import buttondevteam.discordplugin.commands.ICommand2DC;
|
||||
import buttondevteam.lib.TBMCCoreAPI;
|
||||
import buttondevteam.lib.chat.Command2;
|
||||
import buttondevteam.lib.chat.CommandClass;
|
||||
import lombok.val;
|
||||
|
||||
@CommandClass(helpText = {
|
||||
"MC Chat",
|
||||
"This command enables or disables the Minecraft chat in private messages.", //
|
||||
"It can be useful if you don't want your messages to be visible, for example when talking in a private channel.", //
|
||||
"You can also run all of the ingame commands you have access to using this command, if you have your accounts connected." //
|
||||
})
|
||||
public class MCChatCommand extends ICommand2DC {
|
||||
|
||||
@Command2.Subcommand
|
||||
public boolean def(Command2DCSender sender) {
|
||||
val message = sender.getMessage();
|
||||
if (!message.getChannel().isPrivate()) {
|
||||
message.reply("this command can only be issued in a direct message with the bot.");
|
||||
return true;
|
||||
}
|
||||
try (final DiscordPlayer user = DiscordPlayer.getUser(message.getAuthor().getStringID(), DiscordPlayer.class)) {
|
||||
boolean mcchat = !user.isMinecraftChatEnabled();
|
||||
MCChatPrivate.privateMCChat(message.getChannel(), mcchat, message.getAuthor(), user);
|
||||
message.reply("Minecraft chat " + (mcchat //
|
||||
? "enabled. Use '" + DiscordPlugin.getPrefix() + "mcchat' again to turn it off." //
|
||||
: "disabled."));
|
||||
} catch (Exception e) {
|
||||
TBMCCoreAPI.SendException("Error while setting mcchat for user" + message.getAuthor().getName(), e);
|
||||
}
|
||||
return true;
|
||||
} // TODO: Pin channel switching to indicate the current channel
|
||||
|
||||
}
|
|
@ -1,74 +0,0 @@
|
|||
package buttondevteam.discordplugin.mcchat;
|
||||
|
||||
import buttondevteam.core.component.channel.Channel;
|
||||
import buttondevteam.core.component.channel.ChatRoom;
|
||||
import buttondevteam.discordplugin.DiscordConnectedPlayer;
|
||||
import buttondevteam.lib.TBMCSystemChatEvent;
|
||||
import lombok.NonNull;
|
||||
import lombok.val;
|
||||
import sx.blah.discord.handle.obj.IChannel;
|
||||
import sx.blah.discord.handle.obj.IUser;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
public class MCChatCustom {
|
||||
/**
|
||||
* Used for town or nation chats or anything else
|
||||
*/
|
||||
static ArrayList<CustomLMD> lastmsgCustom = new ArrayList<>();
|
||||
|
||||
public static void addCustomChat(IChannel channel, String groupid, Channel mcchannel, IUser user, DiscordConnectedPlayer dcp, int toggles, Set<TBMCSystemChatEvent.BroadcastTarget> brtoggles) {
|
||||
if (mcchannel instanceof ChatRoom) {
|
||||
((ChatRoom) mcchannel).joinRoom(dcp);
|
||||
if (groupid == null) groupid = mcchannel.getGroupID(dcp);
|
||||
}
|
||||
val lmd = new CustomLMD(channel, user, groupid, mcchannel, dcp, toggles, brtoggles);
|
||||
lastmsgCustom.add(lmd);
|
||||
}
|
||||
|
||||
public static boolean hasCustomChat(IChannel channel) {
|
||||
return lastmsgCustom.stream().anyMatch(lmd -> lmd.channel.getLongID() == channel.getLongID());
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public static CustomLMD getCustomChat(IChannel channel) {
|
||||
return lastmsgCustom.stream().filter(lmd -> lmd.channel.getLongID() == channel.getLongID()).findAny().orElse(null);
|
||||
}
|
||||
|
||||
public static boolean removeCustomChat(IChannel channel) {
|
||||
MCChatUtils.lastmsgfromd.remove(channel.getLongID());
|
||||
return lastmsgCustom.removeIf(lmd -> {
|
||||
if (lmd.channel.getLongID() != channel.getLongID())
|
||||
return false;
|
||||
if (lmd.mcchannel instanceof ChatRoom)
|
||||
((ChatRoom) lmd.mcchannel).leaveRoom(lmd.dcp);
|
||||
return true;
|
||||
});
|
||||
}
|
||||
|
||||
public static List<CustomLMD> getCustomChats() {
|
||||
return Collections.unmodifiableList(lastmsgCustom);
|
||||
}
|
||||
|
||||
public static class CustomLMD extends MCChatUtils.LastMsgData {
|
||||
public final String groupID;
|
||||
public final Channel mcchannel;
|
||||
public final DiscordConnectedPlayer dcp;
|
||||
public int toggles;
|
||||
public Set<TBMCSystemChatEvent.BroadcastTarget> brtoggles;
|
||||
|
||||
private CustomLMD(@NonNull IChannel channel, @NonNull IUser user,
|
||||
@NonNull String groupid, @NonNull Channel mcchannel, @NonNull DiscordConnectedPlayer dcp, int toggles, Set<TBMCSystemChatEvent.BroadcastTarget> brtoggles) {
|
||||
super(channel, user);
|
||||
groupID = groupid;
|
||||
this.mcchannel = mcchannel;
|
||||
this.dcp = dcp;
|
||||
this.toggles = toggles;
|
||||
this.brtoggles = brtoggles;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,410 +0,0 @@
|
|||
package buttondevteam.discordplugin.mcchat;
|
||||
|
||||
import buttondevteam.core.ComponentManager;
|
||||
import buttondevteam.core.component.channel.Channel;
|
||||
import buttondevteam.core.component.channel.ChatRoom;
|
||||
import buttondevteam.discordplugin.DPUtils;
|
||||
import buttondevteam.discordplugin.DiscordPlugin;
|
||||
import buttondevteam.discordplugin.DiscordSender;
|
||||
import buttondevteam.discordplugin.DiscordSenderBase;
|
||||
import buttondevteam.discordplugin.listeners.CommandListener;
|
||||
import buttondevteam.discordplugin.playerfaker.VanillaCommandListener;
|
||||
import buttondevteam.lib.*;
|
||||
import buttondevteam.lib.chat.ChatMessage;
|
||||
import buttondevteam.lib.chat.TBMCChatAPI;
|
||||
import buttondevteam.lib.player.TBMCPlayer;
|
||||
import com.vdurmont.emoji.EmojiParser;
|
||||
import lombok.val;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.event.EventHandler;
|
||||
import org.bukkit.event.Listener;
|
||||
import org.bukkit.scheduler.BukkitTask;
|
||||
import sx.blah.discord.api.internal.json.objects.EmbedObject;
|
||||
import sx.blah.discord.handle.impl.events.guild.channel.message.MessageReceivedEvent;
|
||||
import sx.blah.discord.handle.obj.IChannel;
|
||||
import sx.blah.discord.handle.obj.IMessage;
|
||||
import sx.blah.discord.handle.obj.IUser;
|
||||
import sx.blah.discord.util.DiscordException;
|
||||
import sx.blah.discord.util.EmbedBuilder;
|
||||
import sx.blah.discord.util.MissingPermissionsException;
|
||||
|
||||
import java.awt.*;
|
||||
import java.time.Instant;
|
||||
import java.util.AbstractMap;
|
||||
import java.util.Arrays;
|
||||
import java.util.Optional;
|
||||
import java.util.concurrent.LinkedBlockingQueue;
|
||||
import java.util.concurrent.TimeoutException;
|
||||
import java.util.function.Function;
|
||||
import java.util.function.Predicate;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
public class MCChatListener implements Listener {
|
||||
private BukkitTask sendtask;
|
||||
private LinkedBlockingQueue<AbstractMap.SimpleEntry<TBMCChatEvent, Instant>> sendevents = new LinkedBlockingQueue<>();
|
||||
private Runnable sendrunnable;
|
||||
private static Thread sendthread;
|
||||
private final MinecraftChatModule module;
|
||||
|
||||
public MCChatListener(MinecraftChatModule minecraftChatModule) {
|
||||
module = minecraftChatModule;
|
||||
}
|
||||
|
||||
@EventHandler // Minecraft
|
||||
public void onMCChat(TBMCChatEvent ev) {
|
||||
if (!ComponentManager.isEnabled(MinecraftChatModule.class) || ev.isCancelled()) //SafeMode: Needed so it doesn't restart after server shutdown
|
||||
return;
|
||||
sendevents.add(new AbstractMap.SimpleEntry<>(ev, Instant.now()));
|
||||
if (sendtask != null)
|
||||
return;
|
||||
sendrunnable = () -> {
|
||||
sendthread = Thread.currentThread();
|
||||
processMCToDiscord();
|
||||
if (DiscordPlugin.plugin.isEnabled()) //Don't run again if shutting down
|
||||
sendtask = Bukkit.getScheduler().runTaskAsynchronously(DiscordPlugin.plugin, sendrunnable);
|
||||
};
|
||||
sendtask = Bukkit.getScheduler().runTaskAsynchronously(DiscordPlugin.plugin, sendrunnable);
|
||||
}
|
||||
|
||||
private void processMCToDiscord() {
|
||||
try {
|
||||
TBMCChatEvent e;
|
||||
Instant time;
|
||||
val se = sendevents.take(); // Wait until an element is available
|
||||
e = se.getKey();
|
||||
time = se.getValue();
|
||||
|
||||
final String authorPlayer = "[" + DPUtils.sanitizeStringNoEscape(e.getChannel().DisplayName().get()) + "] " //
|
||||
+ ("Minecraft".equals(e.getOrigin()) ? "" : "[" + e.getOrigin().substring(0, 1) + "]") //
|
||||
+ (DPUtils.sanitizeStringNoEscape(e.getSender() instanceof Player //
|
||||
? ((Player) e.getSender()).getDisplayName() //
|
||||
: e.getSender().getName()));
|
||||
val color = e.getChannel().Color().get();
|
||||
final EmbedBuilder embed = new EmbedBuilder().withAuthorName(authorPlayer)
|
||||
.withDescription(e.getMessage()).withColor(new Color(color.getRed(),
|
||||
color.getGreen(), color.getBlue()));
|
||||
// embed.appendField("Channel", ((e.getSender() instanceof DiscordSenderBase ? "d|" : "")
|
||||
// + DiscordPlugin.sanitizeString(e.getChannel().DisplayName)), false);
|
||||
if (e.getSender() instanceof Player)
|
||||
DPUtils.embedWithHead(
|
||||
embed.withAuthorUrl("https://tbmcplugins.github.io/profile.html?type=minecraft&id="
|
||||
+ ((Player) e.getSender()).getUniqueId()),
|
||||
e.getSender().getName());
|
||||
else if (e.getSender() instanceof DiscordSenderBase)
|
||||
embed.withAuthorIcon(((DiscordSenderBase) e.getSender()).getUser().getAvatarURL())
|
||||
.withAuthorUrl("https://tbmcplugins.github.io/profile.html?type=discord&id="
|
||||
+ ((DiscordSenderBase) e.getSender()).getUser().getStringID()); // TODO: Constant/method to get URLs like this
|
||||
// embed.withFooterText(e.getChannel().DisplayName);
|
||||
embed.withTimestamp(time);
|
||||
final long nanoTime = System.nanoTime();
|
||||
InterruptibleConsumer<MCChatUtils.LastMsgData> doit = lastmsgdata -> {
|
||||
final EmbedObject embedObject = embed.build();
|
||||
if (lastmsgdata.message == null || lastmsgdata.message.isDeleted()
|
||||
|| !authorPlayer.equals(lastmsgdata.message.getEmbeds().get(0).getAuthor().getName())
|
||||
|| lastmsgdata.time / 1000000000f < nanoTime / 1000000000f - 120
|
||||
|| !lastmsgdata.mcchannel.ID.equals(e.getChannel().ID)) {
|
||||
lastmsgdata.message = DiscordPlugin.sendMessageToChannelWait(lastmsgdata.channel, "",
|
||||
embedObject); // TODO Use ChromaBot API
|
||||
lastmsgdata.time = nanoTime;
|
||||
lastmsgdata.mcchannel = e.getChannel();
|
||||
lastmsgdata.content = embedObject.description;
|
||||
} else
|
||||
try {
|
||||
lastmsgdata.content = embedObject.description = lastmsgdata.content + "\n"
|
||||
+ embedObject.description;// The message object doesn't get updated
|
||||
final MCChatUtils.LastMsgData _lastmsgdata = lastmsgdata;
|
||||
DPUtils.perform(() -> _lastmsgdata.message.edit("", embedObject));
|
||||
} catch (MissingPermissionsException | DiscordException e1) {
|
||||
TBMCCoreAPI.SendException("An error occurred while editing chat message!", e1);
|
||||
}
|
||||
};
|
||||
// Checks if the given channel is different than where the message was sent from
|
||||
// Or if it was from MC
|
||||
Predicate<IChannel> isdifferentchannel = ch -> !(e.getSender() instanceof DiscordSenderBase)
|
||||
|| ((DiscordSenderBase) e.getSender()).getChannel().getLongID() != ch.getLongID();
|
||||
|
||||
if (e.getChannel().isGlobal()
|
||||
&& (e.isFromCommand() || isdifferentchannel.test(module.chatChannel().get())))
|
||||
doit.accept(MCChatUtils.lastmsgdata == null
|
||||
? MCChatUtils.lastmsgdata = new MCChatUtils.LastMsgData(module.chatChannel().get(), null)
|
||||
: MCChatUtils.lastmsgdata);
|
||||
|
||||
for (MCChatUtils.LastMsgData data : MCChatPrivate.lastmsgPerUser) {
|
||||
if ((e.isFromCommand() || isdifferentchannel.test(data.channel))
|
||||
&& e.shouldSendTo(MCChatUtils.getSender(data.channel, data.user)))
|
||||
doit.accept(data);
|
||||
}
|
||||
|
||||
val iterator = MCChatCustom.lastmsgCustom.iterator();
|
||||
while (iterator.hasNext()) {
|
||||
val lmd = iterator.next();
|
||||
if ((e.isFromCommand() || isdifferentchannel.test(lmd.channel)) //Test if msg is from Discord
|
||||
&& e.getChannel().ID.equals(lmd.mcchannel.ID) //If it's from a command, the command msg has been deleted, so we need to send it
|
||||
&& e.getGroupID().equals(lmd.groupID)) { //Check if this is the group we want to test - #58
|
||||
if (e.shouldSendTo(lmd.dcp)) //Check original user's permissions
|
||||
doit.accept(lmd);
|
||||
else {
|
||||
iterator.remove(); //If the user no longer has permission, remove the connection
|
||||
DiscordPlugin.sendMessageToChannel(lmd.channel, "The user no longer has permission to view the channel, connection removed.");
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (InterruptedException ex) { //Stop if interrupted anywhere
|
||||
sendtask.cancel();
|
||||
sendtask = null;
|
||||
} catch (Exception ex) {
|
||||
TBMCCoreAPI.SendException("Error while sending message to Discord!", ex);
|
||||
}
|
||||
}
|
||||
|
||||
@EventHandler
|
||||
public void onChatPreprocess(TBMCChatPreprocessEvent event) {
|
||||
int start = -1;
|
||||
while ((start = event.getMessage().indexOf('@', start + 1)) != -1) {
|
||||
int mid = event.getMessage().indexOf('#', start + 1);
|
||||
if (mid == -1)
|
||||
return;
|
||||
int end_ = event.getMessage().indexOf(' ', mid + 1);
|
||||
if (end_ == -1)
|
||||
end_ = event.getMessage().length();
|
||||
final int end = end_;
|
||||
final int startF = start;
|
||||
DiscordPlugin.dc.getUsersByName(event.getMessage().substring(start + 1, mid)).stream()
|
||||
.filter(u -> u.getDiscriminator().equals(event.getMessage().substring(mid + 1, end))).findAny()
|
||||
.ifPresent(user -> event.setMessage(event.getMessage().substring(0, startF) + "@" + user.getName()
|
||||
+ (event.getMessage().length() > end ? event.getMessage().substring(end) : ""))); // TODO: Add formatting
|
||||
start = end; // Skip any @s inside the mention
|
||||
}
|
||||
}
|
||||
|
||||
// ......................DiscordSender....DiscordConnectedPlayer.DiscordPlayerSender
|
||||
// Offline public chat......x............................................
|
||||
// Online public chat.......x...........................................x
|
||||
// Offline private chat.....x.......................x....................
|
||||
// Online private chat......x.......................x...................x
|
||||
// If online and enabling private chat, don't login
|
||||
// If leaving the server and private chat is enabled (has ConnectedPlayer), call login in a task on lowest priority
|
||||
// If private chat is enabled and joining the server, logout the fake player on highest priority
|
||||
// If online and disabling private chat, don't logout
|
||||
// The maps may not contain the senders for UnconnectedSenders
|
||||
|
||||
/**
|
||||
* Stop the listener. Any calls to onMCChat will restart it as long as we're not in safe mode.
|
||||
*
|
||||
* @param wait Wait 5 seconds for the threads to stop
|
||||
*/
|
||||
public static void stop(boolean wait) {
|
||||
if (sendthread != null) sendthread.interrupt();
|
||||
if (recthread != null) recthread.interrupt();
|
||||
try {
|
||||
if (sendthread != null) {
|
||||
sendthread.interrupt();
|
||||
if (wait)
|
||||
sendthread.join(5000);
|
||||
}
|
||||
if (recthread != null) {
|
||||
recthread.interrupt();
|
||||
if (wait)
|
||||
recthread.join(5000);
|
||||
}
|
||||
MCChatUtils.lastmsgdata = null;
|
||||
MCChatPrivate.lastmsgPerUser.clear();
|
||||
MCChatCustom.lastmsgCustom.clear();
|
||||
MCChatUtils.lastmsgfromd.clear();
|
||||
MCChatUtils.ConnectedSenders.clear();
|
||||
MCChatUtils.UnconnectedSenders.clear();
|
||||
recthread = sendthread = null;
|
||||
} catch (InterruptedException e) {
|
||||
e.printStackTrace(); //This thread shouldn't be interrupted
|
||||
}
|
||||
}
|
||||
|
||||
private BukkitTask rectask;
|
||||
private LinkedBlockingQueue<MessageReceivedEvent> recevents = new LinkedBlockingQueue<>();
|
||||
private Runnable recrun;
|
||||
private static Thread recthread;
|
||||
|
||||
// Discord
|
||||
public boolean handleDiscord(MessageReceivedEvent ev) {
|
||||
if (!ComponentManager.isEnabled(MinecraftChatModule.class))
|
||||
return false;
|
||||
val author = ev.getMessage().getAuthor();
|
||||
final boolean hasCustomChat = MCChatCustom.hasCustomChat(ev.getChannel());
|
||||
if (ev.getMessage().getChannel().getLongID() != module.chatChannel().get().getLongID()
|
||||
&& !(ev.getMessage().getChannel().isPrivate() && MCChatPrivate.isMinecraftChatEnabled(author.getStringID()))
|
||||
&& !hasCustomChat)
|
||||
return false; //Chat isn't enabled on this channel
|
||||
if (ev.getMessage().getChannel().isPrivate() //Only in private chat
|
||||
&& ev.getMessage().getContent().length() < "/mcchat<>".length()
|
||||
&& ev.getMessage().getContent().replace("/", "")
|
||||
.equalsIgnoreCase("mcchat")) //Either mcchat or /mcchat
|
||||
return false; //Allow disabling the chat if needed
|
||||
if (CommandListener.runCommand(ev.getMessage(), true))
|
||||
return true; //Allow running commands in chat channels
|
||||
MCChatUtils.resetLastMessage(ev.getChannel());
|
||||
recevents.add(ev);
|
||||
if (rectask != null)
|
||||
return true;
|
||||
recrun = () -> { //Don't return in a while loop next time
|
||||
recthread = Thread.currentThread();
|
||||
processDiscordToMC();
|
||||
if (DiscordPlugin.plugin.isEnabled()) //Don't run again if shutting down
|
||||
rectask = Bukkit.getScheduler().runTaskAsynchronously(DiscordPlugin.plugin, recrun); //Continue message processing
|
||||
};
|
||||
rectask = Bukkit.getScheduler().runTaskAsynchronously(DiscordPlugin.plugin, recrun); //Start message processing
|
||||
return true;
|
||||
}
|
||||
|
||||
private void processDiscordToMC() {
|
||||
@val
|
||||
sx.blah.discord.handle.impl.events.guild.channel.message.MessageReceivedEvent event;
|
||||
try {
|
||||
event = recevents.take();
|
||||
} catch (InterruptedException e1) {
|
||||
rectask.cancel();
|
||||
return;
|
||||
}
|
||||
val sender = event.getMessage().getAuthor();
|
||||
String dmessage = event.getMessage().getContent();
|
||||
try {
|
||||
final DiscordSenderBase dsender = MCChatUtils.getSender(event.getMessage().getChannel(), sender);
|
||||
val user = dsender.getChromaUser();
|
||||
|
||||
for (IUser u : event.getMessage().getMentions()) {
|
||||
dmessage = dmessage.replace(u.mention(false), "@" + u.getName()); // TODO: IG Formatting
|
||||
final String nick = u.getNicknameForGuild(DiscordPlugin.mainServer);
|
||||
dmessage = dmessage.replace(u.mention(true), "@" + (nick != null ? nick : u.getName()));
|
||||
}
|
||||
for (IChannel ch : event.getMessage().getChannelMentions()) {
|
||||
dmessage = dmessage.replace(ch.mention(), "#" + ch.getName()); // TODO: IG Formatting
|
||||
}
|
||||
|
||||
dmessage = EmojiParser.parseToAliases(dmessage, EmojiParser.FitzpatrickAction.PARSE); //Converts emoji to text- TODO: Add option to disable (resource pack?)
|
||||
dmessage = dmessage.replaceAll(":(\\S+)\\|type_(?:(\\d)|(1)_2):", ":$1::skin-tone-$2:"); //Convert to Discord's format so it still shows up
|
||||
|
||||
Function<String, String> getChatMessage = msg -> //
|
||||
msg + (event.getMessage().getAttachments().size() > 0 ? "\n" + event.getMessage()
|
||||
.getAttachments().stream().map(IMessage.Attachment::getUrl).collect(Collectors.joining("\n"))
|
||||
: "");
|
||||
|
||||
MCChatCustom.CustomLMD clmd = MCChatCustom.getCustomChat(event.getChannel());
|
||||
|
||||
boolean react = false;
|
||||
|
||||
if (dmessage.startsWith("/")) { // Ingame command
|
||||
DPUtils.perform(() -> {
|
||||
if (!event.getMessage().isDeleted() && !event.getChannel().isPrivate())
|
||||
event.getMessage().delete();
|
||||
});
|
||||
final String cmd = dmessage.substring(1);
|
||||
final String cmdlowercased = cmd.toLowerCase();
|
||||
if (dsender instanceof DiscordSender && module.whitelistedCommands().get().stream()
|
||||
.noneMatch(s -> cmdlowercased.equals(s) || cmdlowercased.startsWith(s + " "))) {
|
||||
// Command not whitelisted
|
||||
dsender.sendMessage("Sorry, you can only access these commands:\n"
|
||||
+ module.whitelistedCommands().get().stream().map(uc -> "/" + uc)
|
||||
.collect(Collectors.joining(", "))
|
||||
+ (user.getConnectedID(TBMCPlayer.class) == null
|
||||
? "\nTo access your commands, first please connect your accounts, using /connect in "
|
||||
+ DPUtils.botmention()
|
||||
+ "\nThen y"
|
||||
: "\nY")
|
||||
+ "ou can access all of your regular commands (even offline) in private chat: DM me `mcchat`!");
|
||||
return;
|
||||
}
|
||||
val ev = new TBMCCommandPreprocessEvent(dsender, dmessage);
|
||||
Bukkit.getPluginManager().callEvent(ev);
|
||||
if (ev.isCancelled())
|
||||
return;
|
||||
int spi = cmdlowercased.indexOf(' ');
|
||||
final String topcmd = spi == -1 ? cmdlowercased : cmdlowercased.substring(0, spi);
|
||||
Optional<Channel> ch = Channel.getChannels()
|
||||
.filter(c -> c.ID.equalsIgnoreCase(topcmd)
|
||||
|| (c.IDs().get().length > 0
|
||||
&& Arrays.stream(c.IDs().get()).anyMatch(id -> id.equalsIgnoreCase(topcmd)))).findAny();
|
||||
if (!ch.isPresent()) //TODO: What if talking in the public chat while we have it on a different one
|
||||
Bukkit.getScheduler().runTask(DiscordPlugin.plugin, //Commands need to be run sync
|
||||
() -> { //TODO: Better handling...
|
||||
val channel = user.channel();
|
||||
val chtmp = channel.get();
|
||||
if (clmd != null) {
|
||||
channel.set(clmd.mcchannel); //Hack to send command in the channel
|
||||
} //TODO: Permcheck isn't implemented for commands
|
||||
VanillaCommandListener.runBukkitOrVanillaCommand(dsender, cmd);
|
||||
Bukkit.getLogger().info(dsender.getName() + " issued command from Discord: /" + cmdlowercased);
|
||||
if (clmd != null)
|
||||
channel.set(chtmp);
|
||||
});
|
||||
else {
|
||||
Channel chc = ch.get();
|
||||
if (!chc.isGlobal() && !event.getMessage().getChannel().isPrivate())
|
||||
dsender.sendMessage(
|
||||
"You can only talk in a public chat here. DM `mcchat` to enable private chat to talk in the other channels.");
|
||||
else {
|
||||
if (spi == -1) // Switch channels
|
||||
{
|
||||
val channel = dsender.getChromaUser().channel();
|
||||
val oldch = channel.get();
|
||||
if (oldch instanceof ChatRoom)
|
||||
((ChatRoom) oldch).leaveRoom(dsender);
|
||||
if (!oldch.ID.equals(chc.ID)) {
|
||||
channel.set(chc);
|
||||
if (chc instanceof ChatRoom)
|
||||
((ChatRoom) chc).joinRoom(dsender);
|
||||
} else
|
||||
channel.set(Channel.GlobalChat);
|
||||
dsender.sendMessage("You're now talking in: "
|
||||
+ DPUtils.sanitizeString(channel.get().DisplayName().get()));
|
||||
} else { // Send single message
|
||||
final String msg = cmd.substring(spi + 1);
|
||||
val cmb = ChatMessage.builder(dsender, user, getChatMessage.apply(msg)).fromCommand(true);
|
||||
if (clmd == null)
|
||||
TBMCChatAPI.SendChatMessage(cmb.build(), chc);
|
||||
else
|
||||
TBMCChatAPI.SendChatMessage(cmb.permCheck(clmd.dcp).build(), chc);
|
||||
react = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {// Not a command
|
||||
if (dmessage.length() == 0 && event.getMessage().getAttachments().size() == 0
|
||||
&& !event.getChannel().isPrivate() && event.getMessage().isSystemMessage()) {
|
||||
val rtr = clmd != null ? clmd.mcchannel.getRTR(clmd.dcp)
|
||||
: dsender.getChromaUser().channel().get().getRTR(dsender);
|
||||
TBMCChatAPI.SendSystemMessage(clmd != null ? clmd.mcchannel : dsender.getChromaUser().channel().get(), rtr,
|
||||
(dsender instanceof Player ? ((Player) dsender).getDisplayName()
|
||||
: dsender.getName()) + " pinned a message on Discord.", TBMCSystemChatEvent.BroadcastTarget.ALL);
|
||||
}
|
||||
else {
|
||||
val cmb = ChatMessage.builder(dsender, user, getChatMessage.apply(dmessage)).fromCommand(false);
|
||||
if (clmd != null)
|
||||
TBMCChatAPI.SendChatMessage(cmb.permCheck(clmd.dcp).build(), clmd.mcchannel);
|
||||
else
|
||||
TBMCChatAPI.SendChatMessage(cmb.build());
|
||||
react = true;
|
||||
}
|
||||
}
|
||||
if (react) {
|
||||
try {
|
||||
val lmfd = MCChatUtils.lastmsgfromd.get(event.getChannel().getLongID());
|
||||
if (lmfd != null) {
|
||||
DPUtils.perform(() -> lmfd.removeReaction(DiscordPlugin.dc.getOurUser(),
|
||||
DiscordPlugin.DELIVERED_REACTION)); // Remove it no matter what, we know it's there 99.99% of the time
|
||||
}
|
||||
} catch (Exception e) {
|
||||
TBMCCoreAPI.SendException("An error occured while removing reactions from chat!", e);
|
||||
}
|
||||
MCChatUtils.lastmsgfromd.put(event.getChannel().getLongID(), event.getMessage());
|
||||
DPUtils.perform(() -> event.getMessage().addReaction(DiscordPlugin.DELIVERED_REACTION));
|
||||
}
|
||||
} catch (Exception e) {
|
||||
TBMCCoreAPI.SendException("An error occured while handling message \"" + dmessage + "\"!", e);
|
||||
}
|
||||
}
|
||||
|
||||
@FunctionalInterface
|
||||
private interface InterruptibleConsumer<T> {
|
||||
void accept(T value) throws TimeoutException, InterruptedException;
|
||||
}
|
||||
}
|
|
@ -1,68 +0,0 @@
|
|||
package buttondevteam.discordplugin.mcchat;
|
||||
|
||||
import buttondevteam.discordplugin.DiscordConnectedPlayer;
|
||||
import buttondevteam.discordplugin.DiscordPlayer;
|
||||
import buttondevteam.discordplugin.DiscordPlugin;
|
||||
import buttondevteam.lib.player.TBMCPlayer;
|
||||
import lombok.val;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.event.Event;
|
||||
import org.bukkit.event.player.PlayerJoinEvent;
|
||||
import org.bukkit.event.player.PlayerQuitEvent;
|
||||
import sx.blah.discord.handle.obj.IChannel;
|
||||
import sx.blah.discord.handle.obj.IPrivateChannel;
|
||||
import sx.blah.discord.handle.obj.IUser;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
||||
public class MCChatPrivate {
|
||||
|
||||
/**
|
||||
* Used for messages in PMs (mcchat).
|
||||
*/
|
||||
static ArrayList<MCChatUtils.LastMsgData> lastmsgPerUser = new ArrayList<>();
|
||||
|
||||
public static boolean privateMCChat(IChannel channel, boolean start, IUser user, DiscordPlayer dp) {
|
||||
TBMCPlayer mcp = dp.getAs(TBMCPlayer.class);
|
||||
if (mcp != null) { // If the accounts aren't connected, can't make a connected sender
|
||||
val p = Bukkit.getPlayer(mcp.getUUID());
|
||||
val op = Bukkit.getOfflinePlayer(mcp.getUUID());
|
||||
if (start) {
|
||||
val sender = new DiscordConnectedPlayer(user, channel, mcp.getUUID(), op.getName());
|
||||
MCChatUtils.addSender(MCChatUtils.ConnectedSenders, user, sender);
|
||||
if (p == null)// Player is offline - If the player is online, that takes precedence
|
||||
callEventSync(new PlayerJoinEvent(sender, ""));
|
||||
} else {
|
||||
val sender = MCChatUtils.removeSender(MCChatUtils.ConnectedSenders, channel, user);
|
||||
if (p == null)// Player is offline - If the player is online, that takes precedence
|
||||
callEventSync(new PlayerQuitEvent(sender, ""));
|
||||
}
|
||||
} // ---- PermissionsEx warning is normal on logout ----
|
||||
if (!start)
|
||||
MCChatUtils.lastmsgfromd.remove(channel.getLongID());
|
||||
return start //
|
||||
? lastmsgPerUser.add(new MCChatUtils.LastMsgData(channel, user)) // Doesn't support group DMs
|
||||
: lastmsgPerUser.removeIf(lmd -> lmd.channel.getLongID() == channel.getLongID());
|
||||
}
|
||||
|
||||
public static boolean isMinecraftChatEnabled(DiscordPlayer dp) {
|
||||
return isMinecraftChatEnabled(dp.getDiscordID());
|
||||
}
|
||||
|
||||
public static boolean isMinecraftChatEnabled(String did) { // Don't load the player data just for this
|
||||
return lastmsgPerUser.stream()
|
||||
.anyMatch(lmd -> ((IPrivateChannel) lmd.channel).getRecipient().getStringID().equals(did));
|
||||
}
|
||||
|
||||
public static void logoutAll() {
|
||||
for (val entry : MCChatUtils.ConnectedSenders.entrySet())
|
||||
for (val valueEntry : entry.getValue().entrySet())
|
||||
if (MCChatUtils.getSender(MCChatUtils.OnlineSenders, valueEntry.getKey(), valueEntry.getValue().getUser()) == null) //If the player is online then the fake player was already logged out
|
||||
MCChatUtils.callEventExcludingSome(new PlayerQuitEvent(valueEntry.getValue(), "")); //This is sync
|
||||
MCChatUtils.ConnectedSenders.clear();
|
||||
}
|
||||
|
||||
private static void callEventSync(Event event) {
|
||||
Bukkit.getScheduler().runTask(DiscordPlugin.plugin, () -> MCChatUtils.callEventExcludingSome(event));
|
||||
}
|
||||
}
|
|
@ -1,296 +0,0 @@
|
|||
package buttondevteam.discordplugin.mcchat;
|
||||
|
||||
import buttondevteam.core.ComponentManager;
|
||||
import buttondevteam.core.component.channel.Channel;
|
||||
import buttondevteam.discordplugin.*;
|
||||
import buttondevteam.discordplugin.broadcaster.GeneralEventBroadcasterModule;
|
||||
import buttondevteam.lib.TBMCSystemChatEvent;
|
||||
import io.netty.util.collection.LongObjectHashMap;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.experimental.var;
|
||||
import lombok.val;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.command.CommandSender;
|
||||
import org.bukkit.event.Event;
|
||||
import org.bukkit.event.HandlerList;
|
||||
import org.bukkit.plugin.AuthorNagException;
|
||||
import org.bukkit.plugin.Plugin;
|
||||
import org.bukkit.plugin.RegisteredListener;
|
||||
import sx.blah.discord.handle.obj.IChannel;
|
||||
import sx.blah.discord.handle.obj.IMessage;
|
||||
import sx.blah.discord.handle.obj.IUser;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
import java.util.Arrays;
|
||||
import java.util.HashMap;
|
||||
import java.util.Optional;
|
||||
import java.util.function.Consumer;
|
||||
import java.util.function.Supplier;
|
||||
import java.util.logging.Level;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
public class MCChatUtils {
|
||||
/**
|
||||
* May contain P<DiscordID> as key for public chat
|
||||
*/
|
||||
public static final HashMap<String, HashMap<IChannel, DiscordSender>> UnconnectedSenders = new HashMap<>();
|
||||
public static final HashMap<String, HashMap<IChannel, DiscordConnectedPlayer>> ConnectedSenders = new HashMap<>();
|
||||
/**
|
||||
* May contain P<DiscordID> as key for public chat
|
||||
*/
|
||||
public static final HashMap<String, HashMap<IChannel, DiscordPlayerSender>> OnlineSenders = new HashMap<>();
|
||||
static @Nullable LastMsgData lastmsgdata;
|
||||
static LongObjectHashMap<IMessage> lastmsgfromd = new LongObjectHashMap<>(); // Last message sent by a Discord user, used for clearing checkmarks
|
||||
private static MinecraftChatModule module;
|
||||
|
||||
public static void updatePlayerList() {
|
||||
if (notEnabled()) return;
|
||||
DPUtils.performNoWait(() -> {
|
||||
if (lastmsgdata != null)
|
||||
updatePL(lastmsgdata);
|
||||
MCChatCustom.lastmsgCustom.forEach(MCChatUtils::updatePL);
|
||||
});
|
||||
}
|
||||
|
||||
private static boolean notEnabled() {
|
||||
return getModule() == null;
|
||||
}
|
||||
|
||||
private static MinecraftChatModule getModule() {
|
||||
if (module == null) module = ComponentManager.getIfEnabled(MinecraftChatModule.class);
|
||||
else if (!module.isEnabled()) module = null; //Reset if disabled
|
||||
return module;
|
||||
}
|
||||
|
||||
private static void updatePL(LastMsgData lmd) {
|
||||
String topic = lmd.channel.getTopic();
|
||||
if (topic == null || topic.length() == 0)
|
||||
topic = ".\n----\nMinecraft chat\n----\n.";
|
||||
String[] s = topic.split("\\n----\\n");
|
||||
if (s.length < 3)
|
||||
return;
|
||||
s[0] = Bukkit.getOnlinePlayers().size() + " player" + (Bukkit.getOnlinePlayers().size() != 1 ? "s" : "")
|
||||
+ " online";
|
||||
s[s.length - 1] = "Players: " + Bukkit.getOnlinePlayers().stream()
|
||||
.map(p -> DPUtils.sanitizeString(p.getDisplayName())).collect(Collectors.joining(", "));
|
||||
lmd.channel.changeTopic(String.join("\n----\n", s));
|
||||
}
|
||||
|
||||
public static <T extends DiscordSenderBase> T addSender(HashMap<String, HashMap<IChannel, T>> senders,
|
||||
IUser user, T sender) {
|
||||
return addSender(senders, user.getStringID(), sender);
|
||||
}
|
||||
|
||||
public static <T extends DiscordSenderBase> T addSender(HashMap<String, HashMap<IChannel, T>> senders,
|
||||
String did, T sender) {
|
||||
var map = senders.get(did);
|
||||
if (map == null)
|
||||
map = new HashMap<>();
|
||||
map.put(sender.getChannel(), sender);
|
||||
senders.put(did, map);
|
||||
return sender;
|
||||
}
|
||||
|
||||
public static <T extends DiscordSenderBase> T getSender(HashMap<String, HashMap<IChannel, T>> senders,
|
||||
IChannel channel, IUser user) {
|
||||
var map = senders.get(user.getStringID());
|
||||
if (map != null)
|
||||
return map.get(channel);
|
||||
return null;
|
||||
}
|
||||
|
||||
public static <T extends DiscordSenderBase> T removeSender(HashMap<String, HashMap<IChannel, T>> senders,
|
||||
IChannel channel, IUser user) {
|
||||
var map = senders.get(user.getStringID());
|
||||
if (map != null)
|
||||
return map.remove(channel);
|
||||
return null;
|
||||
}
|
||||
|
||||
public static void forAllMCChat(Consumer<IChannel> action) {
|
||||
if (notEnabled()) return;
|
||||
action.accept(module.chatChannel().get());
|
||||
for (LastMsgData data : MCChatPrivate.lastmsgPerUser)
|
||||
action.accept(data.channel);
|
||||
// lastmsgCustom.forEach(cc -> action.accept(cc.channel)); - Only send relevant messages to custom chat
|
||||
}
|
||||
|
||||
/**
|
||||
* For custom and all MC chat
|
||||
*
|
||||
* @param action The action to act
|
||||
* @param toggle The toggle to check
|
||||
* @param hookmsg Whether the message is also sent from the hook
|
||||
*/
|
||||
public static void forCustomAndAllMCChat(Consumer<IChannel> action, @Nullable ChannelconBroadcast toggle, boolean hookmsg) {
|
||||
if (notEnabled()) return;
|
||||
if (!GeneralEventBroadcasterModule.isHooked() || !hookmsg)
|
||||
forAllMCChat(action);
|
||||
final Consumer<MCChatCustom.CustomLMD> customLMDConsumer = cc -> action.accept(cc.channel);
|
||||
if (toggle == null)
|
||||
MCChatCustom.lastmsgCustom.forEach(customLMDConsumer);
|
||||
else
|
||||
MCChatCustom.lastmsgCustom.stream().filter(cc -> (cc.toggles & toggle.flag) != 0).forEach(customLMDConsumer);
|
||||
}
|
||||
|
||||
/**
|
||||
* Do the {@code action} for each custom chat the {@code sender} have access to and has that broadcast type enabled.
|
||||
*
|
||||
* @param action The action to do
|
||||
* @param sender The sender to check perms of or null to send to all that has it toggled
|
||||
* @param toggle The toggle to check or null to send to all allowed
|
||||
*/
|
||||
public static void forAllowedCustomMCChat(Consumer<IChannel> action, @Nullable CommandSender sender, @Nullable ChannelconBroadcast toggle) {
|
||||
if (notEnabled()) return;
|
||||
MCChatCustom.lastmsgCustom.stream().filter(clmd -> {
|
||||
//new TBMCChannelConnectFakeEvent(sender, clmd.mcchannel).shouldSendTo(clmd.dcp) - Thought it was this simple hehe - Wait, it *should* be this simple
|
||||
if (toggle != null && (clmd.toggles & toggle.flag) == 0)
|
||||
return false; //If null then allow
|
||||
if (sender == null)
|
||||
return true;
|
||||
return clmd.groupID.equals(clmd.mcchannel.getGroupID(sender));
|
||||
}).forEach(cc -> action.accept(cc.channel)); //TODO: Send error messages on channel connect
|
||||
}
|
||||
|
||||
/**
|
||||
* Do the {@code action} for each custom chat the {@code sender} have access to and has that broadcast type enabled.
|
||||
*
|
||||
* @param action The action to do
|
||||
* @param sender The sender to check perms of or null to send to all that has it toggled
|
||||
* @param toggle The toggle to check or null to send to all allowed
|
||||
* @param hookmsg Whether the message is also sent from the hook
|
||||
*/
|
||||
public static void forAllowedCustomAndAllMCChat(Consumer<IChannel> action, @Nullable CommandSender sender, @Nullable ChannelconBroadcast toggle, boolean hookmsg) {
|
||||
if (notEnabled()) return;
|
||||
if (!GeneralEventBroadcasterModule.isHooked() || !hookmsg)
|
||||
forAllMCChat(action);
|
||||
forAllowedCustomMCChat(action, sender, toggle);
|
||||
}
|
||||
|
||||
public static Consumer<IChannel> send(String message) {
|
||||
return ch -> DiscordPlugin.sendMessageToChannel(ch, DPUtils.sanitizeString(message));
|
||||
}
|
||||
|
||||
public static void forAllowedMCChat(Consumer<IChannel> action, TBMCSystemChatEvent event) {
|
||||
if (notEnabled()) return;
|
||||
if (event.getChannel().isGlobal())
|
||||
action.accept(module.chatChannel().get());
|
||||
for (LastMsgData data : MCChatPrivate.lastmsgPerUser)
|
||||
if (event.shouldSendTo(getSender(data.channel, data.user)))
|
||||
action.accept(data.channel);
|
||||
MCChatCustom.lastmsgCustom.stream().filter(clmd -> {
|
||||
if (!clmd.brtoggles.contains(event.getTarget()))
|
||||
return false;
|
||||
return event.shouldSendTo(clmd.dcp);
|
||||
}).map(clmd -> clmd.channel).forEach(action);
|
||||
}
|
||||
|
||||
/**
|
||||
* This method will find the best sender to use: if the player is online, use that, if not but connected then use that etc.
|
||||
*/
|
||||
static DiscordSenderBase getSender(IChannel channel, final IUser author) {
|
||||
//noinspection OptionalGetWithoutIsPresent
|
||||
return Stream.<Supplier<Optional<DiscordSenderBase>>>of( // https://stackoverflow.com/a/28833677/2703239
|
||||
() -> Optional.ofNullable(getSender(OnlineSenders, channel, author)), // Find first non-null
|
||||
() -> Optional.ofNullable(getSender(ConnectedSenders, channel, author)), // This doesn't support the public chat, but it'll always return null for it
|
||||
() -> Optional.ofNullable(getSender(UnconnectedSenders, channel, author)), //
|
||||
() -> Optional.of(addSender(UnconnectedSenders, author,
|
||||
new DiscordSender(author, channel)))).map(Supplier::get).filter(Optional::isPresent).map(Optional::get).findFirst().get();
|
||||
}
|
||||
|
||||
/**
|
||||
* Resets the last message, so it will start a new one instead of appending to it.
|
||||
* This is used when someone (even the bot) sends a message to the channel.
|
||||
*
|
||||
* @param channel The channel to reset in - the process is slightly different for the public, private and custom chats
|
||||
*/
|
||||
public static void resetLastMessage(IChannel channel) {
|
||||
if (notEnabled()) return;
|
||||
if (channel.getLongID() == module.chatChannel().get().getLongID()) {
|
||||
(lastmsgdata == null ? lastmsgdata = new LastMsgData(module.chatChannel().get(), null)
|
||||
: lastmsgdata).message = null;
|
||||
return;
|
||||
} // Don't set the whole object to null, the player and channel information should be preserved
|
||||
for (LastMsgData data : channel.isPrivate() ? MCChatPrivate.lastmsgPerUser : MCChatCustom.lastmsgCustom) {
|
||||
if (data.channel.getLongID() == channel.getLongID()) {
|
||||
data.message = null;
|
||||
return;
|
||||
}
|
||||
}
|
||||
//If it gets here, it's sending a message to a non-chat channel
|
||||
}
|
||||
|
||||
public static void callEventExcludingSome(Event event) {
|
||||
if (notEnabled()) return;
|
||||
callEventExcluding(event, false, module.excludedPlugins().get());
|
||||
}
|
||||
|
||||
/**
|
||||
* Calls an event with the given details.
|
||||
* <p>
|
||||
* This method only synchronizes when the event is not asynchronous.
|
||||
*
|
||||
* @param event Event details
|
||||
* @param only Flips the operation and <b>includes</b> the listed plugins
|
||||
* @param plugins The plugins to exclude. Not case sensitive.
|
||||
*/
|
||||
@SuppressWarnings("WeakerAccess")
|
||||
public static void callEventExcluding(Event event, boolean only, String... plugins) { // Copied from Spigot-API and modified a bit
|
||||
if (event.isAsynchronous()) {
|
||||
if (Thread.holdsLock(Bukkit.getPluginManager())) {
|
||||
throw new IllegalStateException(
|
||||
event.getEventName() + " cannot be triggered asynchronously from inside synchronized code.");
|
||||
}
|
||||
if (Bukkit.getServer().isPrimaryThread()) {
|
||||
throw new IllegalStateException(
|
||||
event.getEventName() + " cannot be triggered asynchronously from primary server thread.");
|
||||
}
|
||||
fireEventExcluding(event, only, plugins);
|
||||
} else {
|
||||
synchronized (Bukkit.getPluginManager()) {
|
||||
fireEventExcluding(event, only, plugins);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static void fireEventExcluding(Event event, boolean only, String... plugins) {
|
||||
HandlerList handlers = event.getHandlers(); // Code taken from SimplePluginManager in Spigot-API
|
||||
RegisteredListener[] listeners = handlers.getRegisteredListeners();
|
||||
val server = Bukkit.getServer();
|
||||
|
||||
for (RegisteredListener registration : listeners) {
|
||||
if (!registration.getPlugin().isEnabled()
|
||||
|| Arrays.stream(plugins).anyMatch(p -> only ^ p.equalsIgnoreCase(registration.getPlugin().getName())))
|
||||
continue; // Modified to exclude plugins
|
||||
|
||||
try {
|
||||
registration.callEvent(event);
|
||||
} catch (AuthorNagException ex) {
|
||||
Plugin plugin = registration.getPlugin();
|
||||
|
||||
if (plugin.isNaggable()) {
|
||||
plugin.setNaggable(false);
|
||||
|
||||
server.getLogger().log(Level.SEVERE,
|
||||
String.format("Nag author(s): '%s' of '%s' about the following: %s",
|
||||
plugin.getDescription().getAuthors(), plugin.getDescription().getFullName(),
|
||||
ex.getMessage()));
|
||||
}
|
||||
} catch (Throwable ex) {
|
||||
server.getLogger().log(Level.SEVERE, "Could not pass event " + event.getEventName() + " to "
|
||||
+ registration.getPlugin().getDescription().getFullName(), ex);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@RequiredArgsConstructor
|
||||
public static class LastMsgData {
|
||||
public IMessage message;
|
||||
public long time;
|
||||
public String content;
|
||||
public final IChannel channel;
|
||||
public Channel mcchannel;
|
||||
public final IUser user;
|
||||
}
|
||||
}
|
|
@ -1,159 +0,0 @@
|
|||
package buttondevteam.discordplugin.mcchat;
|
||||
|
||||
import buttondevteam.discordplugin.*;
|
||||
import buttondevteam.lib.TBMCCoreAPI;
|
||||
import buttondevteam.lib.TBMCSystemChatEvent;
|
||||
import buttondevteam.lib.architecture.ConfigData;
|
||||
import buttondevteam.lib.player.*;
|
||||
import com.earth2me.essentials.CommandSource;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.val;
|
||||
import net.ess3.api.events.AfkStatusChangeEvent;
|
||||
import net.ess3.api.events.MuteStatusChangeEvent;
|
||||
import net.ess3.api.events.NickChangeEvent;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.event.EventHandler;
|
||||
import org.bukkit.event.EventPriority;
|
||||
import org.bukkit.event.Listener;
|
||||
import org.bukkit.event.entity.PlayerDeathEvent;
|
||||
import org.bukkit.event.player.PlayerJoinEvent;
|
||||
import org.bukkit.event.player.PlayerKickEvent;
|
||||
import org.bukkit.event.player.PlayerLoginEvent;
|
||||
import org.bukkit.event.player.PlayerLoginEvent.Result;
|
||||
import org.bukkit.event.player.PlayerQuitEvent;
|
||||
import org.bukkit.event.server.BroadcastMessageEvent;
|
||||
import sx.blah.discord.handle.obj.IRole;
|
||||
import sx.blah.discord.handle.obj.IUser;
|
||||
import sx.blah.discord.util.DiscordException;
|
||||
import sx.blah.discord.util.MissingPermissionsException;
|
||||
|
||||
@RequiredArgsConstructor
|
||||
class MCListener implements Listener {
|
||||
private final MinecraftChatModule module;
|
||||
|
||||
@EventHandler(priority = EventPriority.HIGHEST)
|
||||
public void onPlayerLogin(PlayerLoginEvent e) {
|
||||
if (e.getResult() != Result.ALLOWED)
|
||||
return;
|
||||
MCChatUtils.ConnectedSenders.values().stream().flatMap(v -> v.values().stream()) //Only private mcchat should be in ConnectedSenders
|
||||
.filter(s -> s.getUniqueId().equals(e.getPlayer().getUniqueId())).findAny()
|
||||
.ifPresent(dcp -> MCChatUtils.callEventExcludingSome(new PlayerQuitEvent(dcp, "")));
|
||||
}
|
||||
|
||||
@EventHandler(priority = EventPriority.LOWEST)
|
||||
public void onPlayerJoin(TBMCPlayerJoinEvent e) {
|
||||
if (e.getPlayer() instanceof DiscordConnectedPlayer)
|
||||
return; // Don't show the joined message for the fake player
|
||||
Bukkit.getScheduler().runTaskAsynchronously(DiscordPlugin.plugin, () -> {
|
||||
final Player p = e.getPlayer();
|
||||
DiscordPlayer dp = e.GetPlayer().getAs(DiscordPlayer.class);
|
||||
if (dp != null) {
|
||||
val user = DiscordPlugin.dc.getUserByID(Long.parseLong(dp.getDiscordID()));
|
||||
MCChatUtils.addSender(MCChatUtils.OnlineSenders, dp.getDiscordID(),
|
||||
new DiscordPlayerSender(user, user.getOrCreatePMChannel(), p));
|
||||
MCChatUtils.addSender(MCChatUtils.OnlineSenders, dp.getDiscordID(),
|
||||
new DiscordPlayerSender(user, module.chatChannel().get(), p)); //Stored per-channel
|
||||
}
|
||||
final String message = e.GetPlayer().PlayerName().get() + " joined the game";
|
||||
MCChatUtils.forAllowedCustomAndAllMCChat(MCChatUtils.send(message), e.getPlayer(), ChannelconBroadcast.JOINLEAVE, true);
|
||||
ChromaBot.getInstance().updatePlayerList();
|
||||
});
|
||||
}
|
||||
|
||||
@EventHandler(priority = EventPriority.HIGHEST)
|
||||
public void onPlayerLeave(TBMCPlayerQuitEvent e) {
|
||||
if (e.getPlayer() instanceof DiscordConnectedPlayer)
|
||||
return; // Only care about real users
|
||||
MCChatUtils.OnlineSenders.entrySet()
|
||||
.removeIf(entry -> entry.getValue().entrySet().stream().anyMatch(p -> p.getValue().getUniqueId().equals(e.getPlayer().getUniqueId())));
|
||||
Bukkit.getScheduler().runTask(DiscordPlugin.plugin,
|
||||
() -> MCChatUtils.ConnectedSenders.values().stream().flatMap(v -> v.values().stream())
|
||||
.filter(s -> s.getUniqueId().equals(e.getPlayer().getUniqueId())).findAny()
|
||||
.ifPresent(dcp -> MCChatUtils.callEventExcludingSome(new PlayerJoinEvent(dcp, ""))));
|
||||
Bukkit.getScheduler().runTaskLaterAsynchronously(DiscordPlugin.plugin,
|
||||
ChromaBot.getInstance()::updatePlayerList, 5);
|
||||
final String message = e.GetPlayer().PlayerName().get() + " left the game";
|
||||
MCChatUtils.forAllowedCustomAndAllMCChat(MCChatUtils.send(message), e.getPlayer(), ChannelconBroadcast.JOINLEAVE, true);
|
||||
}
|
||||
|
||||
@EventHandler(priority = EventPriority.HIGHEST)
|
||||
public void onPlayerKick(PlayerKickEvent e) {
|
||||
/*if (!DiscordPlugin.hooked && !e.getReason().equals("The server is restarting")
|
||||
&& !e.getReason().equals("Server closed")) // The leave messages errored with the previous setup, I could make it wait since I moved it here, but instead I have a special
|
||||
MCChatListener.forAllowedCustomAndAllMCChat(e.getPlayer().getName() + " left the game"); // message for this - Oh wait this doesn't even send normally because of the hook*/
|
||||
}
|
||||
|
||||
@EventHandler(priority = EventPriority.LOW)
|
||||
public void onPlayerDeath(PlayerDeathEvent e) {
|
||||
MCChatUtils.forAllowedCustomAndAllMCChat(MCChatUtils.send(e.getDeathMessage()), e.getEntity(), ChannelconBroadcast.DEATH, true);
|
||||
}
|
||||
|
||||
@EventHandler
|
||||
public void onPlayerAFK(AfkStatusChangeEvent e) {
|
||||
final Player base = e.getAffected().getBase();
|
||||
if (e.isCancelled() || !base.isOnline())
|
||||
return;
|
||||
final String msg = base.getDisplayName()
|
||||
+ " is " + (e.getValue() ? "now" : "no longer") + " AFK.";
|
||||
MCChatUtils.forAllowedCustomAndAllMCChat(MCChatUtils.send(msg), base, ChannelconBroadcast.AFK, false);
|
||||
}
|
||||
|
||||
private ConfigData<IRole> muteRole() {
|
||||
return DPUtils.roleData(module.getConfig(), "muteRole", "Muted");
|
||||
}
|
||||
|
||||
@EventHandler
|
||||
public void onPlayerMute(MuteStatusChangeEvent e) {
|
||||
try {
|
||||
DPUtils.performNoWait(() -> {
|
||||
final IRole role = muteRole().get();
|
||||
if (role == null) return;
|
||||
final CommandSource source = e.getAffected().getSource();
|
||||
if (!source.isPlayer())
|
||||
return;
|
||||
final DiscordPlayer p = TBMCPlayerBase.getPlayer(source.getPlayer().getUniqueId(), TBMCPlayer.class)
|
||||
.getAs(DiscordPlayer.class);
|
||||
if (p == null) return;
|
||||
final IUser user = DiscordPlugin.dc.getUserByID(
|
||||
Long.parseLong(p.getDiscordID()));
|
||||
if (e.getValue())
|
||||
user.addRole(role);
|
||||
else
|
||||
user.removeRole(role);
|
||||
val modlog = module.modlogChannel().get();
|
||||
String msg = (e.getValue() ? "M" : "Unm") + "uted user: " + user.getName();
|
||||
if (modlog != null)
|
||||
DiscordPlugin.sendMessageToChannel(modlog, msg);
|
||||
DPUtils.getLogger().info(msg);
|
||||
});
|
||||
} catch (DiscordException | MissingPermissionsException ex) {
|
||||
TBMCCoreAPI.SendException("Failed to give/take Muted role to player " + e.getAffected().getName() + "!",
|
||||
ex);
|
||||
}
|
||||
}
|
||||
|
||||
@EventHandler
|
||||
public void onChatSystemMessage(TBMCSystemChatEvent event) {
|
||||
MCChatUtils.forAllowedMCChat(MCChatUtils.send(event.getMessage()), event);
|
||||
}
|
||||
|
||||
@EventHandler
|
||||
public void onBroadcastMessage(BroadcastMessageEvent event) {
|
||||
MCChatUtils.forCustomAndAllMCChat(MCChatUtils.send(event.getMessage()), ChannelconBroadcast.BROADCAST, false);
|
||||
}
|
||||
|
||||
@EventHandler
|
||||
public void onYEEHAW(TBMCYEEHAWEvent event) { //TODO: Inherit from the chat event base to have channel support
|
||||
String name = event.getSender() instanceof Player ? ((Player) event.getSender()).getDisplayName()
|
||||
: event.getSender().getName();
|
||||
//Channel channel = ChromaGamerBase.getFromSender(event.getSender()).channel().get(); - TODO
|
||||
val yeehaw = DiscordPlugin.mainServer.getEmojiByName("YEEHAW");
|
||||
MCChatUtils.forAllMCChat(MCChatUtils.send(name + (yeehaw != null ? " <:YEEHAW:" + yeehaw.getStringID() + ">s" : " YEEHAWs")));
|
||||
}
|
||||
|
||||
@EventHandler
|
||||
public void onNickChange(NickChangeEvent event) {
|
||||
MCChatUtils.updatePlayerList();
|
||||
}
|
||||
}
|
|
@ -1,112 +0,0 @@
|
|||
package buttondevteam.discordplugin.mcchat;
|
||||
|
||||
import buttondevteam.core.component.channel.Channel;
|
||||
import buttondevteam.discordplugin.DPUtils;
|
||||
import buttondevteam.discordplugin.DiscordConnectedPlayer;
|
||||
import buttondevteam.discordplugin.DiscordPlugin;
|
||||
import buttondevteam.lib.TBMCCoreAPI;
|
||||
import buttondevteam.lib.TBMCSystemChatEvent;
|
||||
import buttondevteam.lib.architecture.Component;
|
||||
import buttondevteam.lib.architecture.ConfigData;
|
||||
import com.google.common.collect.Lists;
|
||||
import lombok.Getter;
|
||||
import lombok.val;
|
||||
import org.bukkit.Bukkit;
|
||||
import sx.blah.discord.handle.obj.IChannel;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Objects;
|
||||
import java.util.UUID;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/**
|
||||
* Provides Minecraft chat connection to Discord. Commands may be used either in a public chat (limited) or in a DM.
|
||||
*/
|
||||
public class MinecraftChatModule extends Component<DiscordPlugin> {
|
||||
private @Getter MCChatListener listener;
|
||||
|
||||
public MCChatListener getListener() { //It doesn't want to generate
|
||||
return listener;
|
||||
}
|
||||
|
||||
/**
|
||||
* A list of commands that can be used in public chats - Warning: Some plugins will treat players as OPs, always test before allowing a command!
|
||||
*/
|
||||
public ConfigData<ArrayList<String>> whitelistedCommands() {
|
||||
return getConfig().getData("whitelistedCommands", () -> Lists.newArrayList("list", "u", "shrug", "tableflip", "unflip", "mwiki",
|
||||
"yeehaw", "lenny", "rp", "plugins"));
|
||||
}
|
||||
|
||||
/**
|
||||
* The channel to use as the public Minecraft chat - everything public gets broadcasted here
|
||||
*/
|
||||
public ConfigData<IChannel> chatChannel() {
|
||||
return DPUtils.channelData(getConfig(), "chatChannel", 239519012529111040L);
|
||||
}
|
||||
|
||||
/**
|
||||
* The channel where the plugin can log when it mutes a player on Discord because of a Minecraft mute
|
||||
*/
|
||||
public ConfigData<IChannel> modlogChannel() {
|
||||
return DPUtils.channelData(getConfig(), "modlogChannel", 283840717275791360L);
|
||||
}
|
||||
|
||||
/**
|
||||
* 0 * The plugins to exclude from fake player events used for the 'mcchat' command - some plugins may crash, add them here
|
||||
*/
|
||||
public ConfigData<String[]> excludedPlugins() {
|
||||
return getConfig().getData("excludedPlugins", new String[]{"ProtocolLib", "LibsDisguises", "JourneyMapServer"});
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void enable() {
|
||||
if (DPUtils.disableIfConfigError(this, chatChannel())) return;
|
||||
listener = new MCChatListener(this);
|
||||
DiscordPlugin.dc.getDispatcher().registerListener(listener);
|
||||
TBMCCoreAPI.RegisterEventsForExceptions(listener, getPlugin());
|
||||
TBMCCoreAPI.RegisterEventsForExceptions(new MCListener(this), getPlugin());//These get undone if restarting/resetting - it will ignore events if disabled
|
||||
getPlugin().getManager().registerCommand(new MCChatCommand());
|
||||
getPlugin().getManager().registerCommand(new ChannelconCommand());
|
||||
|
||||
val chcons = getConfig().getConfig().getConfigurationSection("chcons");
|
||||
if (chcons == null) //Fallback to old place
|
||||
getConfig().getConfig().getRoot().getConfigurationSection("chcons");
|
||||
if (chcons != null) {
|
||||
val chconkeys = chcons.getKeys(false);
|
||||
for (val chconkey : chconkeys) {
|
||||
val chcon = chcons.getConfigurationSection(chconkey);
|
||||
val mcch = Channel.getChannels().filter(ch -> ch.ID.equals(chcon.getString("mcchid"))).findAny();
|
||||
val ch = DiscordPlugin.dc.getChannelByID(chcon.getLong("chid"));
|
||||
val did = chcon.getLong("did");
|
||||
val user = DiscordPlugin.dc.fetchUser(did);
|
||||
val groupid = chcon.getString("groupid");
|
||||
val toggles = chcon.getInt("toggles");
|
||||
val brtoggles = chcon.getStringList("brtoggles");
|
||||
if (!mcch.isPresent() || ch == null || user == null || groupid == null)
|
||||
continue;
|
||||
Bukkit.getScheduler().runTask(getPlugin(), () -> { //<-- Needed because of occasional ConcurrentModificationExceptions when creating the player (PermissibleBase)
|
||||
val dcp = new DiscordConnectedPlayer(user, ch, UUID.fromString(chcon.getString("mcuid")), chcon.getString("mcname"));
|
||||
MCChatCustom.addCustomChat(ch, groupid, mcch.get(), user, dcp, toggles, brtoggles.stream().map(TBMCSystemChatEvent.BroadcastTarget::get).filter(Objects::nonNull).collect(Collectors.toSet()));
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void disable() {
|
||||
val chcons = MCChatCustom.getCustomChats();
|
||||
val chconsc = getConfig().getConfig().createSection("chcons");
|
||||
for (val chcon : chcons) {
|
||||
val chconc = chconsc.createSection(chcon.channel.getStringID());
|
||||
chconc.set("mcchid", chcon.mcchannel.ID);
|
||||
chconc.set("chid", chcon.channel.getLongID());
|
||||
chconc.set("did", chcon.user.getLongID());
|
||||
chconc.set("mcuid", chcon.dcp.getUniqueId().toString());
|
||||
chconc.set("mcname", chcon.dcp.getName());
|
||||
chconc.set("groupid", chcon.groupID);
|
||||
chconc.set("toggles", chcon.toggles);
|
||||
chconc.set("brtoggles", chcon.brtoggles.stream().map(TBMCSystemChatEvent.BroadcastTarget::getName).collect(Collectors.toList()));
|
||||
}
|
||||
MCChatListener.stop(true);
|
||||
}
|
||||
}
|
|
@ -1,44 +0,0 @@
|
|||
package buttondevteam.discordplugin.mccommands;
|
||||
|
||||
import buttondevteam.discordplugin.DPUtils;
|
||||
import buttondevteam.discordplugin.DiscordPlayer;
|
||||
import buttondevteam.discordplugin.commands.ConnectCommand;
|
||||
import buttondevteam.discordplugin.mcchat.MCChatUtils;
|
||||
import buttondevteam.lib.chat.CommandClass;
|
||||
import buttondevteam.lib.player.ChromaGamerBase;
|
||||
import buttondevteam.lib.player.TBMCPlayer;
|
||||
import buttondevteam.lib.player.TBMCPlayerBase;
|
||||
import org.bukkit.entity.Player;
|
||||
|
||||
@CommandClass(modOnly = false, path = "accept")
|
||||
public class AcceptMCCommand extends DiscordMCCommandBase {
|
||||
|
||||
@Override
|
||||
public String[] GetHelpText(String alias) {
|
||||
return new String[] { //
|
||||
"§6---- Accept Discord connection ----", //
|
||||
"Accept a pending connection between your Discord and Minecraft account.", //
|
||||
"To start the connection process, do §b/connect <MCname>§r in the " + DPUtils.botmention() + " channel on Discord", //
|
||||
"Usage: /" + alias + " accept" //
|
||||
};
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean OnCommand(Player player, String alias, String[] args) {
|
||||
String did = ConnectCommand.WaitingToConnect.get(player.getName());
|
||||
if (did == null) {
|
||||
player.sendMessage("§cYou don't have a pending connection to Discord.");
|
||||
return true;
|
||||
}
|
||||
DiscordPlayer dp = ChromaGamerBase.getUser(did, DiscordPlayer.class);
|
||||
TBMCPlayer mcp = TBMCPlayerBase.getPlayer(player.getUniqueId(), TBMCPlayer.class);
|
||||
dp.connectWith(mcp);
|
||||
dp.save();
|
||||
mcp.save();
|
||||
ConnectCommand.WaitingToConnect.remove(player.getName());
|
||||
MCChatUtils.UnconnectedSenders.remove(did); //Remove all unconnected, will be recreated where needed
|
||||
player.sendMessage("§bAccounts connected.");
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
|
@ -1,32 +0,0 @@
|
|||
package buttondevteam.discordplugin.mccommands;
|
||||
|
||||
import buttondevteam.discordplugin.DPUtils;
|
||||
import buttondevteam.discordplugin.commands.ConnectCommand;
|
||||
import buttondevteam.lib.chat.CommandClass;
|
||||
import org.bukkit.entity.Player;
|
||||
|
||||
@CommandClass(modOnly = false, path = "decline")
|
||||
public class DeclineMCCommand extends DiscordMCCommandBase {
|
||||
|
||||
@Override
|
||||
public String[] GetHelpText(String alias) {
|
||||
return new String[] { //
|
||||
"§6---- Decline Discord connection ----", //
|
||||
"Decline a pending connection between your Discord and Minecraft account.", //
|
||||
"To start the connection process, do §b/connect <MCname>§r in the " + DPUtils.botmention() + " channel on Discord", //
|
||||
"Usage: /" + alias + " decline" //
|
||||
};
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean OnCommand(Player player, String alias, String[] args) {
|
||||
String did = ConnectCommand.WaitingToConnect.remove(player.getName());
|
||||
if (did == null) {
|
||||
player.sendMessage("§cYou don't have a pending connection to Discord.");
|
||||
return true;
|
||||
}
|
||||
player.sendMessage("§bPending connection declined.");
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
|
@ -1,9 +0,0 @@
|
|||
package buttondevteam.discordplugin.mccommands;
|
||||
|
||||
import buttondevteam.lib.chat.CommandClass;
|
||||
import buttondevteam.lib.chat.PlayerCommandBase;
|
||||
|
||||
@CommandClass(modOnly = false, path = "discord")
|
||||
public abstract class DiscordMCCommandBase extends PlayerCommandBase {
|
||||
|
||||
}
|
|
@ -1,26 +0,0 @@
|
|||
package buttondevteam.discordplugin.mccommands;
|
||||
|
||||
import buttondevteam.discordplugin.DiscordPlugin;
|
||||
import buttondevteam.lib.chat.CommandClass;
|
||||
import buttondevteam.lib.chat.TBMCCommandBase;
|
||||
import org.bukkit.command.CommandSender;
|
||||
|
||||
@CommandClass(path = "discord reload")
|
||||
public class ReloadMCCommand extends TBMCCommandBase {
|
||||
@Override
|
||||
public boolean OnCommand(CommandSender sender, String alias, String[] args) {
|
||||
if (DiscordPlugin.plugin.tryReloadConfig())
|
||||
sender.sendMessage("§bConfig reloaded."); //TODO: Convert to new command system
|
||||
else
|
||||
sender.sendMessage("§cFailed to reload config.");
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String[] GetHelpText(String alias) {
|
||||
return new String[]{
|
||||
"Reload",
|
||||
"Reloads the config. To apply some changes, you may need to also run /discord reset."
|
||||
};
|
||||
}
|
||||
}
|
|
@ -1,35 +0,0 @@
|
|||
package buttondevteam.discordplugin.mccommands;
|
||||
|
||||
import buttondevteam.discordplugin.DiscordPlugin;
|
||||
import buttondevteam.discordplugin.DiscordSenderBase;
|
||||
import buttondevteam.lib.chat.CommandClass;
|
||||
import buttondevteam.lib.chat.TBMCCommandBase;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.command.CommandSender;
|
||||
|
||||
@CommandClass(path = "discord reset", modOnly = true)
|
||||
public class ResetMCCommand extends TBMCCommandBase { //Not player-only, so not using DiscordMCCommandBase
|
||||
public static boolean resetting = false;
|
||||
@Override
|
||||
public boolean OnCommand(CommandSender sender, String s, String[] strings) {
|
||||
Bukkit.getScheduler().runTaskAsynchronously(DiscordPlugin.plugin, () -> {
|
||||
resetting = true; //Turned off after sending enable message (ReadyEvent)
|
||||
sender.sendMessage("§bDisabling DiscordPlugin...");
|
||||
Bukkit.getPluginManager().disablePlugin(DiscordPlugin.plugin);
|
||||
if (!(sender instanceof DiscordSenderBase)) //Sending to Discord errors
|
||||
sender.sendMessage("§bEnabling DiscordPlugin...");
|
||||
Bukkit.getPluginManager().enablePlugin(DiscordPlugin.plugin);
|
||||
if (!(sender instanceof DiscordSenderBase)) //Sending to Discord errors
|
||||
sender.sendMessage("§bReset finished!");
|
||||
});
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String[] GetHelpText(String s) {
|
||||
return new String[]{ //
|
||||
"§6---- Reset ChromaBot ----", //
|
||||
"This command disables and then enables the plugin." //
|
||||
};
|
||||
}
|
||||
}
|
|
@ -1,20 +0,0 @@
|
|||
package buttondevteam.discordplugin.mccommands;
|
||||
|
||||
import buttondevteam.discordplugin.commands.VersionCommand;
|
||||
import buttondevteam.lib.chat.CommandClass;
|
||||
import buttondevteam.lib.chat.TBMCCommandBase;
|
||||
import org.bukkit.command.CommandSender;
|
||||
|
||||
@CommandClass(path = "discord version")
|
||||
public class VersionMCCommand extends TBMCCommandBase {
|
||||
@Override
|
||||
public boolean OnCommand(CommandSender commandSender, String s, String[] strings) {
|
||||
commandSender.sendMessage(VersionCommand.getVersion());
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String[] GetHelpText(String s) {
|
||||
return VersionCommand.getVersion(); //Heh
|
||||
}
|
||||
}
|
|
@ -1,300 +0,0 @@
|
|||
package buttondevteam.discordplugin.playerfaker;
|
||||
|
||||
import buttondevteam.discordplugin.DiscordSenderBase;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
import org.bukkit.*;
|
||||
import org.bukkit.block.PistonMoveReaction;
|
||||
import org.bukkit.entity.Entity;
|
||||
import org.bukkit.event.entity.EntityDamageEvent;
|
||||
import org.bukkit.event.player.PlayerTeleportEvent.TeleportCause;
|
||||
import org.bukkit.metadata.MetadataValue;
|
||||
import org.bukkit.plugin.Plugin;
|
||||
import org.bukkit.util.Vector;
|
||||
import sx.blah.discord.handle.obj.IChannel;
|
||||
import sx.blah.discord.handle.obj.IUser;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
@Getter
|
||||
@Setter
|
||||
@SuppressWarnings("deprecated")
|
||||
public abstract class DiscordEntity extends DiscordSenderBase implements Entity {
|
||||
protected DiscordEntity(IUser user, IChannel channel, int entityId, UUID uuid) {
|
||||
super(user, channel);
|
||||
this.entityId = entityId;
|
||||
uniqueId = uuid;
|
||||
}
|
||||
|
||||
private HashMap<String, MetadataValue> metadata = new HashMap<String, MetadataValue>();
|
||||
|
||||
private Location location = new Location(Bukkit.getWorlds().get(0), 0, 0, 0);
|
||||
private Vector velocity;
|
||||
private final int entityId;
|
||||
private EntityDamageEvent lastDamageCause;
|
||||
private final Set<String> scoreboardTags = new HashSet<String>();
|
||||
private final UUID uniqueId;
|
||||
|
||||
@Override
|
||||
public void setMetadata(String metadataKey, MetadataValue newMetadataValue) {
|
||||
metadata.put(metadataKey, newMetadataValue);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<MetadataValue> getMetadata(String metadataKey) {
|
||||
return Arrays.asList(metadata.get(metadataKey)); // Who needs multiple data anyways
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasMetadata(String metadataKey) {
|
||||
return metadata.containsKey(metadataKey);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeMetadata(String metadataKey, Plugin owningPlugin) {
|
||||
metadata.remove(metadataKey);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Location getLocation(Location loc) {
|
||||
if (loc != null) {
|
||||
loc.setWorld(getWorld());
|
||||
loc.setX(location.getX());
|
||||
loc.setY(location.getY());
|
||||
loc.setZ(location.getZ());
|
||||
loc.setYaw(location.getYaw());
|
||||
loc.setPitch(location.getPitch());
|
||||
}
|
||||
|
||||
return loc;
|
||||
}
|
||||
|
||||
@Override
|
||||
public double getHeight() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public double getWidth() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isOnGround() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public World getWorld() {
|
||||
return location.getWorld();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean teleport(Location location) {
|
||||
this.location = location;
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean teleport(Location location, TeleportCause cause) {
|
||||
this.location = location;
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean teleport(Entity destination) {
|
||||
this.location = destination.getLocation();
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean teleport(Entity destination, TeleportCause cause) {
|
||||
this.location = destination.getLocation();
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Entity> getNearbyEntities(double x, double y, double z) {
|
||||
return Arrays.asList();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getFireTicks() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getMaxFireTicks() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setFireTicks(int ticks) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void remove() {
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isDead() { // Impossible to kill
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isValid() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Server getServer() {
|
||||
return Bukkit.getServer();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Entity getPassenger() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean setPassenger(Entity passenger) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Entity> getPassengers() {
|
||||
return Arrays.asList();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean addPassenger(Entity passenger) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean removePassenger(Entity passenger) { // Don't support passengers
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isEmpty() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean eject() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public float getFallDistance() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setFallDistance(float distance) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getTicksLived() {
|
||||
return 1;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setTicksLived(int value) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void playEffect(EntityEffect type) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isInsideVehicle() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean leaveVehicle() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Entity getVehicle() { // Don't support vehicles
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setCustomNameVisible(boolean flag) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isCustomNameVisible() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setGlowing(boolean flag) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isGlowing() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setInvulnerable(boolean flag) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isInvulnerable() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isSilent() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setSilent(boolean flag) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasGravity() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setGravity(boolean gravity) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getPortalCooldown() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setPortalCooldown(int cooldown) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean addScoreboardTag(String tag) {
|
||||
return scoreboardTags.add(tag);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean removeScoreboardTag(String tag) {
|
||||
return scoreboardTags.remove(tag);
|
||||
}
|
||||
|
||||
@Override
|
||||
public PistonMoveReaction getPistonMoveReaction() {
|
||||
return PistonMoveReaction.IGNORE;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Entity.Spigot spigot() {
|
||||
return new Entity.Spigot();
|
||||
}
|
||||
|
||||
}
|
|
@ -1,717 +0,0 @@
|
|||
package buttondevteam.discordplugin.playerfaker;
|
||||
|
||||
import buttondevteam.discordplugin.DiscordPlugin;
|
||||
import lombok.Getter;
|
||||
import lombok.experimental.Delegate;
|
||||
import org.bukkit.*;
|
||||
import org.bukkit.advancement.Advancement;
|
||||
import org.bukkit.advancement.AdvancementProgress;
|
||||
import org.bukkit.conversations.Conversation;
|
||||
import org.bukkit.conversations.ConversationAbandonedEvent;
|
||||
import org.bukkit.entity.Entity;
|
||||
import org.bukkit.entity.EntityType;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.event.player.AsyncPlayerChatEvent;
|
||||
import org.bukkit.map.MapView;
|
||||
import org.bukkit.permissions.PermissibleBase;
|
||||
import org.bukkit.plugin.Plugin;
|
||||
import org.bukkit.scoreboard.Scoreboard;
|
||||
import sx.blah.discord.handle.obj.IChannel;
|
||||
import sx.blah.discord.handle.obj.IUser;
|
||||
|
||||
import java.net.InetSocketAddress;
|
||||
import java.util.*;
|
||||
|
||||
@SuppressWarnings("deprecation")
|
||||
public class DiscordFakePlayer extends DiscordHumanEntity implements Player {
|
||||
protected DiscordFakePlayer(IUser user, IChannel channel, int entityId, UUID uuid, String mcname) {
|
||||
super(user, channel, entityId, uuid);
|
||||
perm = new PermissibleBase(Bukkit.getOfflinePlayer(uuid));
|
||||
name = mcname;
|
||||
}
|
||||
|
||||
@Delegate
|
||||
private PermissibleBase perm;
|
||||
|
||||
private @Getter String name;
|
||||
|
||||
@Override
|
||||
public EntityType getType() {
|
||||
return EntityType.PLAYER;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getCustomName() {
|
||||
return user.getName();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setCustomName(String name) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isConversing() {
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void acceptConversationInput(String input) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean beginConversation(Conversation conversation) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void abandonConversation(Conversation conversation) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void abandonConversation(Conversation conversation, ConversationAbandonedEvent details) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isOnline() {
|
||||
return true;// Let's pretend
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isBanned() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isWhitelisted() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setWhitelisted(boolean value) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public Player getPlayer() {
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getFirstPlayed() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getLastPlayed() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasPlayedBefore() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<String, Object> serialize() {
|
||||
return new HashMap<>();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void sendPluginMessage(Plugin source, String channel, byte[] message) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<String> getListeningPluginChannels() {
|
||||
return Collections.emptySet();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getDisplayName() {
|
||||
return user.getDisplayName(DiscordPlugin.mainServer);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setDisplayName(String name) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getPlayerListName() {
|
||||
return getName();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setPlayerListName(String name) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setCompassTarget(Location loc) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public Location getCompassTarget() {
|
||||
return new Location(Bukkit.getWorlds().get(0), 0, 0, 0);
|
||||
}
|
||||
|
||||
@Override
|
||||
public InetSocketAddress getAddress() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void sendRawMessage(String message) {
|
||||
sendMessage(message);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void kickPlayer(String message) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void chat(String msg) {
|
||||
Bukkit.getPluginManager()
|
||||
.callEvent(new AsyncPlayerChatEvent(true, this, msg, new HashSet<>(Bukkit.getOnlinePlayers())));
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean performCommand(String command) {
|
||||
return Bukkit.getServer().dispatchCommand(this, command);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isSneaking() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setSneaking(boolean sneak) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isSprinting() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setSprinting(boolean sprinting) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void saveData() {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void loadData() {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setSleepingIgnored(boolean isSleeping) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isSleepingIgnored() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void playNote(Location loc, byte instrument, byte note) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void playNote(Location loc, Instrument instrument, Note note) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void playSound(Location location, Sound sound, float volume, float pitch) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void playSound(Location location, String sound, float volume, float pitch) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void playSound(Location location, Sound sound, SoundCategory category, float volume, float pitch) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void playSound(Location location, String sound, SoundCategory category, float volume, float pitch) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void stopSound(Sound sound) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void stopSound(String sound) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void stopSound(Sound sound, SoundCategory category) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void stopSound(String sound, SoundCategory category) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void playEffect(Location loc, Effect effect, int data) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> void playEffect(Location loc, Effect effect, T data) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void sendBlockChange(Location loc, Material material, byte data) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean sendChunkChange(Location loc, int sx, int sy, int sz, byte[] data) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void sendBlockChange(Location loc, int material, byte data) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void sendSignChange(Location loc, String[] lines) throws IllegalArgumentException {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void sendMap(MapView map) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateInventory() {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void awardAchievement(@SuppressWarnings("deprecation") Achievement achievement) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeAchievement(@SuppressWarnings("deprecation") Achievement achievement) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasAchievement(@SuppressWarnings("deprecation") Achievement achievement) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void incrementStatistic(Statistic statistic) throws IllegalArgumentException {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void decrementStatistic(Statistic statistic) throws IllegalArgumentException {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void incrementStatistic(Statistic statistic, int amount) throws IllegalArgumentException {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void decrementStatistic(Statistic statistic, int amount) throws IllegalArgumentException {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setStatistic(Statistic statistic, int newValue) throws IllegalArgumentException {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getStatistic(Statistic statistic) throws IllegalArgumentException {
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void incrementStatistic(Statistic statistic, Material material) throws IllegalArgumentException {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void decrementStatistic(Statistic statistic, Material material) throws IllegalArgumentException {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getStatistic(Statistic statistic, Material material) throws IllegalArgumentException {
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void incrementStatistic(Statistic statistic, Material material, int amount) throws IllegalArgumentException {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void decrementStatistic(Statistic statistic, Material material, int amount) throws IllegalArgumentException {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setStatistic(Statistic statistic, Material material, int newValue) throws IllegalArgumentException {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void incrementStatistic(Statistic statistic, EntityType entityType) throws IllegalArgumentException {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void decrementStatistic(Statistic statistic, EntityType entityType) throws IllegalArgumentException {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getStatistic(Statistic statistic, EntityType entityType) throws IllegalArgumentException {
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void incrementStatistic(Statistic statistic, EntityType entityType, int amount)
|
||||
throws IllegalArgumentException {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void decrementStatistic(Statistic statistic, EntityType entityType, int amount) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setStatistic(Statistic statistic, EntityType entityType, int newValue) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setPlayerTime(long time, boolean relative) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getPlayerTime() {
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getPlayerTimeOffset() {
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isPlayerTimeRelative() {
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void resetPlayerTime() {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setPlayerWeather(WeatherType type) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public WeatherType getPlayerWeather() {
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void resetPlayerWeather() {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void giveExp(int amount) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void giveExpLevels(int amount) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public float getExp() {
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setExp(float exp) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getLevel() {
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setLevel(int level) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getTotalExperience() {
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setTotalExperience(int exp) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public float getExhaustion() {
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setExhaustion(float value) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public float getSaturation() {
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setSaturation(float value) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getFoodLevel() {
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setFoodLevel(int value) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public Location getBedSpawnLocation() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setBedSpawnLocation(Location location) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setBedSpawnLocation(Location location, boolean force) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean getAllowFlight() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setAllowFlight(boolean flight) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void hidePlayer(Player player) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void showPlayer(Player player) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean canSee(Player player) { // Nobody can see them
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isFlying() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setFlying(boolean value) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setFlySpeed(float value) throws IllegalArgumentException {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setWalkSpeed(float value) throws IllegalArgumentException {
|
||||
}
|
||||
|
||||
@Override
|
||||
public float getFlySpeed() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public float getWalkSpeed() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setTexturePack(String url) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setResourcePack(String url) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setResourcePack(String url, byte[] hash) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public Scoreboard getScoreboard() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setScoreboard(Scoreboard scoreboard) throws IllegalArgumentException, IllegalStateException {
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isHealthScaled() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setHealthScaled(boolean scale) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setHealthScale(double scale) throws IllegalArgumentException {
|
||||
}
|
||||
|
||||
@Override
|
||||
public double getHealthScale() {
|
||||
return 1;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Entity getSpectatorTarget() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setSpectatorTarget(Entity entity) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void sendTitle(String title, String subtitle) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void sendTitle(String title, String subtitle, int fadeIn, int stay, int fadeOut) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void resetTitle() {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void spawnParticle(Particle particle, Location location, int count) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void spawnParticle(Particle particle, double x, double y, double z, int count) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> void spawnParticle(Particle particle, Location location, int count, T data) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> void spawnParticle(Particle particle, double x, double y, double z, int count, T data) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void spawnParticle(Particle particle, Location location, int count, double offsetX, double offsetY,
|
||||
double offsetZ) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void spawnParticle(Particle particle, double x, double y, double z, int count, double offsetX,
|
||||
double offsetY, double offsetZ) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> void spawnParticle(Particle particle, Location location, int count, double offsetX, double offsetY,
|
||||
double offsetZ, T data) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> void spawnParticle(Particle particle, double x, double y, double z, int count, double offsetX,
|
||||
double offsetY, double offsetZ, T data) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void spawnParticle(Particle particle, Location location, int count, double offsetX, double offsetY,
|
||||
double offsetZ, double extra) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void spawnParticle(Particle particle, double x, double y, double z, int count, double offsetX,
|
||||
double offsetY, double offsetZ, double extra) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> void spawnParticle(Particle particle, Location location, int count, double offsetX, double offsetY,
|
||||
double offsetZ, double extra, T data) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> void spawnParticle(Particle particle, double x, double y, double z, int count, double offsetX,
|
||||
double offsetY, double offsetZ, double extra, T data) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public AdvancementProgress getAdvancementProgress(Advancement advancement) { // TODO: Test
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getLocale() {
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Player.Spigot spigot() {
|
||||
return new Player.Spigot();
|
||||
}
|
||||
}
|
|
@ -1,167 +0,0 @@
|
|||
package buttondevteam.discordplugin.playerfaker;
|
||||
|
||||
import org.bukkit.GameMode;
|
||||
import org.bukkit.Location;
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.entity.Entity;
|
||||
import org.bukkit.entity.HumanEntity;
|
||||
import org.bukkit.entity.Villager;
|
||||
import org.bukkit.inventory.*;
|
||||
import org.bukkit.inventory.InventoryView.Property;
|
||||
import sx.blah.discord.handle.obj.IChannel;
|
||||
import sx.blah.discord.handle.obj.IUser;
|
||||
|
||||
import java.util.UUID;
|
||||
|
||||
public abstract class DiscordHumanEntity extends DiscordLivingEntity implements HumanEntity {
|
||||
protected DiscordHumanEntity(IUser user, IChannel channel, int entityId, UUID uuid) {
|
||||
super(user, channel, entityId, uuid);
|
||||
}
|
||||
|
||||
private PlayerInventory inv = new DiscordPlayerInventory(this);
|
||||
|
||||
@Override
|
||||
public PlayerInventory getInventory() {
|
||||
return inv;
|
||||
}
|
||||
|
||||
private Inventory enderchest = new DiscordInventory(this);
|
||||
|
||||
@Override
|
||||
public Inventory getEnderChest() {
|
||||
return enderchest;
|
||||
}
|
||||
|
||||
@Override
|
||||
public MainHand getMainHand() {
|
||||
return MainHand.RIGHT;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean setWindowProperty(Property prop, int value) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public InventoryView getOpenInventory() { // TODO: Test
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public InventoryView openInventory(Inventory inventory) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public InventoryView openWorkbench(Location location, boolean force) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public InventoryView openEnchanting(Location location, boolean force) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void openInventory(InventoryView inventory) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public InventoryView openMerchant(Villager trader, boolean force) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public InventoryView openMerchant(Merchant merchant, boolean force) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void closeInventory() {
|
||||
}
|
||||
|
||||
@Override
|
||||
public ItemStack getItemInHand() { // TODO: Test all ItemStack methods
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setItemInHand(ItemStack item) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public ItemStack getItemOnCursor() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setItemOnCursor(ItemStack item) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasCooldown(Material material) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getCooldown(Material material) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setCooldown(Material material, int ticks) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isSleeping() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getSleepTicks() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public GameMode getGameMode() {
|
||||
return GameMode.SPECTATOR;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setGameMode(GameMode mode) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isBlocking() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isHandRaised() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getExpToLevel() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Entity getShoulderEntityLeft() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setShoulderEntityLeft(Entity entity) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public Entity getShoulderEntityRight() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setShoulderEntityRight(Entity entity) {
|
||||
}
|
||||
|
||||
}
|
|
@ -1,212 +0,0 @@
|
|||
package buttondevteam.discordplugin.playerfaker;
|
||||
|
||||
import org.bukkit.Location;
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.entity.HumanEntity;
|
||||
import org.bukkit.event.inventory.InventoryType;
|
||||
import org.bukkit.inventory.Inventory;
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.ListIterator;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.IntStream;
|
||||
|
||||
public class DiscordInventory implements Inventory {
|
||||
public DiscordInventory(DiscordHumanEntity holder) {
|
||||
this.holder = holder;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getSize() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getMaxStackSize() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setMaxStackSize(int size) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return "Player inventory";
|
||||
}
|
||||
|
||||
@Override
|
||||
public ItemStack getItem(int index) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public HashMap<Integer, ItemStack> addItem(ItemStack... items) throws IllegalArgumentException { // Can't add anything
|
||||
return new HashMap<>(
|
||||
IntStream.range(0, items.length).boxed().collect(Collectors.toMap(i -> i, i -> items[i])));
|
||||
}
|
||||
|
||||
@Override
|
||||
public HashMap<Integer, ItemStack> removeItem(ItemStack... items) throws IllegalArgumentException {
|
||||
return new HashMap<>(
|
||||
IntStream.range(0, items.length).boxed().collect(Collectors.toMap(i -> i, i -> items[i])));
|
||||
}
|
||||
|
||||
@Override
|
||||
public ItemStack[] getContents() {
|
||||
return new ItemStack[0];
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setContents(ItemStack[] items) throws IllegalArgumentException {
|
||||
if (items.length > 0)
|
||||
throw new IllegalArgumentException("This inventory does not support items");
|
||||
}
|
||||
|
||||
@Override
|
||||
public ItemStack[] getStorageContents() {
|
||||
return new ItemStack[0];
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setStorageContents(ItemStack[] items) throws IllegalArgumentException {
|
||||
if (items.length > 0)
|
||||
throw new IllegalArgumentException("This inventory does not support items");
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean contains(int materialId) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean contains(Material material) throws IllegalArgumentException {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean contains(ItemStack item) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean contains(int materialId, int amount) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean contains(Material material, int amount) throws IllegalArgumentException {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean contains(ItemStack item, int amount) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean containsAtLeast(ItemStack item, int amount) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public HashMap<Integer, ? extends ItemStack> all(int materialId) {
|
||||
return new HashMap<>();
|
||||
}
|
||||
|
||||
@Override
|
||||
public HashMap<Integer, ? extends ItemStack> all(Material material) throws IllegalArgumentException {
|
||||
return new HashMap<>();
|
||||
}
|
||||
|
||||
@Override
|
||||