Compare commits
111 commits
Author | SHA1 | Date | |
---|---|---|---|
66c1b1b14f | |||
496af97e1c | |||
6ec63b5ae7 | |||
ea7520d99a | |||
|
47461d49c2 | ||
7120e3c40e | |||
|
c6b2dc3443 | ||
4e58ddd475 | |||
5c83b923da | |||
83b5f1fec4 | |||
|
59ccc55f98 | ||
f92cc773c1 | |||
2a008906f4 | |||
9fb35eb6cc | |||
66be5ab0dc | |||
5b5a8877cc | |||
09074f1a2e | |||
ff0d54e00b | |||
5199482053 | |||
c12a24895e | |||
51e0ca4f4c | |||
267a350473 | |||
132eba7db6 | |||
83ecf7717f | |||
893b24ed5f | |||
af0aed65e0 | |||
47dbb987eb | |||
|
28e26ad3d1 | ||
|
8e664d073f | ||
1aa9cd3552 | |||
731065fe2a | |||
01dd8a477e | |||
ab4dd75684 | |||
5b27af8925 | |||
28e44d5179 | |||
cedeca2f61 | |||
784ad5e1c7 | |||
9923f26698 | |||
b89391f84c | |||
8f610c9935 | |||
4310e45a6f | |||
43b7bd442a | |||
ef96ec2604 | |||
8815877bea | |||
58fcd4c145 | |||
1139f832b6 | |||
9dae442950 | |||
82858b0a41 | |||
7b505bb8e9 | |||
6b68bdab0f | |||
8344adff1a | |||
f5406a8c0e | |||
95a8e92b51 | |||
792a127bdd | |||
a3160c4040 | |||
b77871bb8c | |||
e676ea516c | |||
0e88c61b77 | |||
425cbcd9d2 | |||
00738fe820 | |||
3c4f9f6c7a | |||
2cca2e2096 | |||
59aa13cd74 | |||
05720afdf8 | |||
393c9c9b08 | |||
a0c211f4be | |||
def4a846b2 | |||
b9781f19f0 | |||
b7260d318c | |||
dd1f42d420 | |||
c947c887a1 | |||
23f3c0f133 | |||
d2ab3511c2 | |||
8f6ee349de | |||
220829a206 | |||
9aa320e663 | |||
d48a2d17d3 | |||
6491a4e732 | |||
a1919c04d0 | |||
1a4829e894 | |||
5da07565b0 | |||
cecd8df991 | |||
fa18e8f22a | |||
89c27a10c6 | |||
fb9c108c52 | |||
34637ac536 | |||
dea1a46f55 | |||
8f75998b58 | |||
0e4eee55ac | |||
65419ac20d | |||
7de1d0575c | |||
2f62d2b962 | |||
0c5345d3ff | |||
d100b86d72 | |||
dd64062fba | |||
7b29f00105 | |||
383e9dc8d5 | |||
1a6bd29741 | |||
ed4a4da37f | |||
17ac28b9b7 | |||
bb10f9fb0f | |||
0967095f59 | |||
317b5a3bda | |||
a17923602f | |||
feee6a0ebe | |||
2ad7a757c6 | |||
14bcebabcd | |||
fa6c453a8d | |||
773277cb27 | |||
a39fd083be | |||
db8dfa79bc |
166 changed files with 4143 additions and 4287 deletions
|
@ -13,3 +13,5 @@ tab_width=4
|
||||||
indent_style=space
|
indent_style=space
|
||||||
indent_size=2
|
indent_size=2
|
||||||
|
|
||||||
|
[*.xml]
|
||||||
|
indent_style = tab
|
||||||
|
|
75
.github/workflows/codeql-analysis.yml
vendored
Normal file
75
.github/workflows/codeql-analysis.yml
vendored
Normal file
|
@ -0,0 +1,75 @@
|
||||||
|
# For most projects, this workflow file will not need changing; you simply need
|
||||||
|
# to commit it to your repository.
|
||||||
|
#
|
||||||
|
# You may wish to alter this file to override the set of languages analyzed,
|
||||||
|
# or to provide custom queries or build logic.
|
||||||
|
name: "CodeQL"
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
branches: [ master ]
|
||||||
|
pull_request:
|
||||||
|
# The branches below must be a subset of the branches above
|
||||||
|
branches: [ master ]
|
||||||
|
schedule:
|
||||||
|
- cron: '0 10 * * 1'
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
analyze:
|
||||||
|
name: Analyze
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
|
||||||
|
strategy:
|
||||||
|
fail-fast: false
|
||||||
|
matrix:
|
||||||
|
# Override automatic language detection by changing the below list
|
||||||
|
# Supported options are ['csharp', 'cpp', 'go', 'java', 'javascript', 'python']
|
||||||
|
language: [ 'java' ]
|
||||||
|
# Learn more...
|
||||||
|
# https://docs.github.com/en/github/finding-security-vulnerabilities-and-errors-in-your-code/configuring-code-scanning#overriding-automatic-language-detection
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- name: Setup Java JDK
|
||||||
|
uses: actions/setup-java@v1.3.0
|
||||||
|
with:
|
||||||
|
java-version: 11
|
||||||
|
- name: Checkout repository
|
||||||
|
uses: actions/checkout@v2
|
||||||
|
with:
|
||||||
|
# We must fetch at least the immediate parents so that if this is
|
||||||
|
# a pull request then we can checkout the head.
|
||||||
|
fetch-depth: 2
|
||||||
|
|
||||||
|
# If this run was triggered by a pull request event, then checkout
|
||||||
|
# the head of the pull request instead of the merge commit.
|
||||||
|
- run: git checkout HEAD^2
|
||||||
|
if: ${{ github.event_name == 'pull_request' }}
|
||||||
|
|
||||||
|
# Initializes the CodeQL tools for scanning.
|
||||||
|
- name: Initialize CodeQL
|
||||||
|
uses: github/codeql-action/init@v1
|
||||||
|
with:
|
||||||
|
languages: ${{ matrix.language }}
|
||||||
|
# If you wish to specify custom queries, you can do so here or in a config file.
|
||||||
|
# By default, queries listed here will override any specified in a config file.
|
||||||
|
# Prefix the list here with "+" to use these queries and those in the config file.
|
||||||
|
# queries: ./path/to/local/query, your-org/your-repo/queries@main
|
||||||
|
|
||||||
|
# Autobuild attempts to build any compiled languages (C/C++, C#, or Java).
|
||||||
|
# If this step fails, then you should remove it and run the build manually (see below)
|
||||||
|
- name: Autobuild
|
||||||
|
uses: github/codeql-action/autobuild@v1
|
||||||
|
|
||||||
|
# ℹ️ Command-line programs to run using the OS shell.
|
||||||
|
# 📚 https://git.io/JvXDl
|
||||||
|
|
||||||
|
# ✏️ If the Autobuild fails above, remove it and uncomment the following three lines
|
||||||
|
# and modify them (or add more) to build your code if your project
|
||||||
|
# uses a compiled language
|
||||||
|
|
||||||
|
#- run: |
|
||||||
|
# make bootstrap
|
||||||
|
# make release
|
||||||
|
|
||||||
|
- name: Perform CodeQL Analysis
|
||||||
|
uses: github/codeql-action/analyze@v1
|
6
.gitignore
vendored
6
.gitignore
vendored
|
@ -218,10 +218,10 @@ pip-log.txt
|
||||||
.mr.developer.cfg
|
.mr.developer.cfg
|
||||||
.metadata/*
|
.metadata/*
|
||||||
TheButtonAutoFlair/out/artifacts/Autoflair/Autoflair.jar
|
TheButtonAutoFlair/out/artifacts/Autoflair/Autoflair.jar
|
||||||
#*.iml
|
*.iml
|
||||||
*.name
|
*.name
|
||||||
.idea/compiler.xml
|
.idea
|
||||||
*.xml
|
dependency-reduced-pom.xml
|
||||||
|
|
||||||
TBMC/
|
TBMC/
|
||||||
/.apt_generated/
|
/.apt_generated/
|
||||||
|
|
|
@ -1,13 +0,0 @@
|
||||||
<?xml version="1.0" encoding="UTF-8"?>
|
|
||||||
<module org.jetbrains.idea.maven.project.MavenProjectsManager.isMavenModule="true" type="JAVA_MODULE" version="4">
|
|
||||||
<component name="NewModuleRootManager" LANGUAGE_LEVEL="JDK_1_5">
|
|
||||||
<output url="file://$MODULE_DIR$/target/classes" />
|
|
||||||
<output-test url="file://$MODULE_DIR$/target/test-classes" />
|
|
||||||
<content url="file://$MODULE_DIR$">
|
|
||||||
<excludeFolder url="file://$MODULE_DIR$/target" />
|
|
||||||
</content>
|
|
||||||
<orderEntry type="inheritedJdk" />
|
|
||||||
<orderEntry type="sourceFolder" forTests="false" />
|
|
||||||
<orderEntry type="library" scope="TEST" name="Maven: junit:junit:3.8.1" level="project" />
|
|
||||||
</component>
|
|
||||||
</module>
|
|
|
@ -1,5 +0,0 @@
|
||||||
<component name="ProjectCodeStyleConfiguration">
|
|
||||||
<state>
|
|
||||||
<option name="PREFERRED_PROJECT_CODE_STYLE" value="Default" />
|
|
||||||
</state>
|
|
||||||
</component>
|
|
|
@ -1,28 +0,0 @@
|
||||||
<?xml version="1.0" encoding="UTF-8"?>
|
|
||||||
<project version="4">
|
|
||||||
<component name="CompilerConfiguration">
|
|
||||||
<annotationProcessing>
|
|
||||||
<profile default="true" name="Default" enabled="true" />
|
|
||||||
<profile name="Maven default annotation processors profile" enabled="true">
|
|
||||||
<sourceOutputDir name="target/generated-sources/annotations" />
|
|
||||||
<sourceTestOutputDir name="target/generated-test-sources/test-annotations" />
|
|
||||||
<outputRelativeToContentRoot value="true" />
|
|
||||||
<module name="BuildConfigUpdater" />
|
|
||||||
<module name="ButtonCore (1) (com.github.TBMCPlugins.ButtonCore)" />
|
|
||||||
</profile>
|
|
||||||
</annotationProcessing>
|
|
||||||
<bytecodeTargetLevel>
|
|
||||||
<module name="BuildConfigUpdater" target="1.8" />
|
|
||||||
<module name="ButtonCore" target="1.5" />
|
|
||||||
<module name="ButtonCore (1) (com.github.TBMCPlugins.ButtonCore)" target="1.8" />
|
|
||||||
<module name="ButtonProcessor" target="1.8" />
|
|
||||||
<module name="ChunkArchive" target="1.8" />
|
|
||||||
<module name="RandomTeleport" target="1.8" />
|
|
||||||
</bytecodeTargetLevel>
|
|
||||||
</component>
|
|
||||||
<component name="JavacSettings">
|
|
||||||
<option name="ADDITIONAL_OPTIONS_OVERRIDE">
|
|
||||||
<module name="ButtonProcessor" options="-proc:none" />
|
|
||||||
</option>
|
|
||||||
</component>
|
|
||||||
</project>
|
|
|
@ -1,7 +0,0 @@
|
||||||
<?xml version="1.0" encoding="UTF-8"?>
|
|
||||||
<project version="4">
|
|
||||||
<component name="Encoding">
|
|
||||||
<file url="file://$PROJECT_DIR$/ButtonCore" charset="UTF-8" />
|
|
||||||
<file url="file://$PROJECT_DIR$/ButtonProcessor" charset="UTF-8" />
|
|
||||||
</component>
|
|
||||||
</project>
|
|
|
@ -1,11 +0,0 @@
|
||||||
<component name="InspectionProjectProfileManager">
|
|
||||||
<profile version="1.0">
|
|
||||||
<option name="myName" value="Project Default" />
|
|
||||||
<inspection_tool class="WeakerAccess" enabled="false" level="WARNING" enabled_by_default="false">
|
|
||||||
<option name="SUGGEST_PACKAGE_LOCAL_FOR_MEMBERS" value="false" />
|
|
||||||
<option name="SUGGEST_PACKAGE_LOCAL_FOR_TOP_CLASSES" value="false" />
|
|
||||||
<option name="SUGGEST_PRIVATE_FOR_INNERS" value="false" />
|
|
||||||
<disabledExtension id="moduleInfo" />
|
|
||||||
</inspection_tool>
|
|
||||||
</profile>
|
|
||||||
</component>
|
|
|
@ -1,13 +0,0 @@
|
||||||
<component name="libraryTable">
|
|
||||||
<library name="Maven: com.google.code.findbugs:annotations:2.0.1">
|
|
||||||
<CLASSES>
|
|
||||||
<root url="jar://$MAVEN_REPOSITORY$/com/google/code/findbugs/annotations/2.0.1/annotations-2.0.1.jar!/" />
|
|
||||||
</CLASSES>
|
|
||||||
<JAVADOC>
|
|
||||||
<root url="jar://$MAVEN_REPOSITORY$/com/google/code/findbugs/annotations/2.0.1/annotations-2.0.1-javadoc.jar!/" />
|
|
||||||
</JAVADOC>
|
|
||||||
<SOURCES>
|
|
||||||
<root url="jar://$MAVEN_REPOSITORY$/com/google/code/findbugs/annotations/2.0.1/annotations-2.0.1-sources.jar!/" />
|
|
||||||
</SOURCES>
|
|
||||||
</library>
|
|
||||||
</component>
|
|
|
@ -1,13 +0,0 @@
|
||||||
<component name="libraryTable">
|
|
||||||
<library name="Maven: com.google.code.gson:gson:2.8.0">
|
|
||||||
<CLASSES>
|
|
||||||
<root url="jar://$MAVEN_REPOSITORY$/com/google/code/gson/gson/2.8.0/gson-2.8.0.jar!/" />
|
|
||||||
</CLASSES>
|
|
||||||
<JAVADOC>
|
|
||||||
<root url="jar://$MAVEN_REPOSITORY$/com/google/code/gson/gson/2.8.0/gson-2.8.0-javadoc.jar!/" />
|
|
||||||
</JAVADOC>
|
|
||||||
<SOURCES>
|
|
||||||
<root url="jar://$MAVEN_REPOSITORY$/com/google/code/gson/gson/2.8.0/gson-2.8.0-sources.jar!/" />
|
|
||||||
</SOURCES>
|
|
||||||
</library>
|
|
||||||
</component>
|
|
|
@ -1,13 +0,0 @@
|
||||||
<component name="libraryTable">
|
|
||||||
<library name="Maven: com.google.guava:guava:15.0">
|
|
||||||
<CLASSES>
|
|
||||||
<root url="jar://$MAVEN_REPOSITORY$/com/google/guava/guava/15.0/guava-15.0.jar!/" />
|
|
||||||
</CLASSES>
|
|
||||||
<JAVADOC>
|
|
||||||
<root url="jar://$MAVEN_REPOSITORY$/com/google/guava/guava/15.0/guava-15.0-javadoc.jar!/" />
|
|
||||||
</JAVADOC>
|
|
||||||
<SOURCES>
|
|
||||||
<root url="jar://$MAVEN_REPOSITORY$/com/google/guava/guava/15.0/guava-15.0-sources.jar!/" />
|
|
||||||
</SOURCES>
|
|
||||||
</library>
|
|
||||||
</component>
|
|
|
@ -1,13 +0,0 @@
|
||||||
<component name="libraryTable">
|
|
||||||
<library name="Maven: com.google.guava:guava:21.0">
|
|
||||||
<CLASSES>
|
|
||||||
<root url="jar://$MAVEN_REPOSITORY$/com/google/guava/guava/21.0/guava-21.0.jar!/" />
|
|
||||||
</CLASSES>
|
|
||||||
<JAVADOC>
|
|
||||||
<root url="jar://$MAVEN_REPOSITORY$/com/google/guava/guava/21.0/guava-21.0-javadoc.jar!/" />
|
|
||||||
</JAVADOC>
|
|
||||||
<SOURCES>
|
|
||||||
<root url="jar://$MAVEN_REPOSITORY$/com/google/guava/guava/21.0/guava-21.0-sources.jar!/" />
|
|
||||||
</SOURCES>
|
|
||||||
</library>
|
|
||||||
</component>
|
|
|
@ -1,13 +0,0 @@
|
||||||
<component name="libraryTable">
|
|
||||||
<library name="Maven: com.googlecode.json-simple:json-simple:1.1.1">
|
|
||||||
<CLASSES>
|
|
||||||
<root url="jar://$MAVEN_REPOSITORY$/com/googlecode/json-simple/json-simple/1.1.1/json-simple-1.1.1.jar!/" />
|
|
||||||
</CLASSES>
|
|
||||||
<JAVADOC>
|
|
||||||
<root url="jar://$MAVEN_REPOSITORY$/com/googlecode/json-simple/json-simple/1.1.1/json-simple-1.1.1-javadoc.jar!/" />
|
|
||||||
</JAVADOC>
|
|
||||||
<SOURCES>
|
|
||||||
<root url="jar://$MAVEN_REPOSITORY$/com/googlecode/json-simple/json-simple/1.1.1/json-simple-1.1.1-sources.jar!/" />
|
|
||||||
</SOURCES>
|
|
||||||
</library>
|
|
||||||
</component>
|
|
|
@ -1,13 +0,0 @@
|
||||||
<component name="libraryTable">
|
|
||||||
<library name="Maven: commons-io:commons-io:1.3.2">
|
|
||||||
<CLASSES>
|
|
||||||
<root url="jar://$MAVEN_REPOSITORY$/commons-io/commons-io/1.3.2/commons-io-1.3.2.jar!/" />
|
|
||||||
</CLASSES>
|
|
||||||
<JAVADOC>
|
|
||||||
<root url="jar://$MAVEN_REPOSITORY$/commons-io/commons-io/1.3.2/commons-io-1.3.2-javadoc.jar!/" />
|
|
||||||
</JAVADOC>
|
|
||||||
<SOURCES>
|
|
||||||
<root url="jar://$MAVEN_REPOSITORY$/commons-io/commons-io/1.3.2/commons-io-1.3.2-sources.jar!/" />
|
|
||||||
</SOURCES>
|
|
||||||
</library>
|
|
||||||
</component>
|
|
|
@ -1,13 +0,0 @@
|
||||||
<component name="libraryTable">
|
|
||||||
<library name="Maven: commons-io:commons-io:2.6">
|
|
||||||
<CLASSES>
|
|
||||||
<root url="jar://$MAVEN_REPOSITORY$/commons-io/commons-io/2.6/commons-io-2.6.jar!/" />
|
|
||||||
</CLASSES>
|
|
||||||
<JAVADOC>
|
|
||||||
<root url="jar://$MAVEN_REPOSITORY$/commons-io/commons-io/2.6/commons-io-2.6-javadoc.jar!/" />
|
|
||||||
</JAVADOC>
|
|
||||||
<SOURCES>
|
|
||||||
<root url="jar://$MAVEN_REPOSITORY$/commons-io/commons-io/2.6/commons-io-2.6-sources.jar!/" />
|
|
||||||
</SOURCES>
|
|
||||||
</library>
|
|
||||||
</component>
|
|
|
@ -1,13 +0,0 @@
|
||||||
<component name="libraryTable">
|
|
||||||
<library name="Maven: commons-lang:commons-lang:2.6">
|
|
||||||
<CLASSES>
|
|
||||||
<root url="jar://$MAVEN_REPOSITORY$/commons-lang/commons-lang/2.6/commons-lang-2.6.jar!/" />
|
|
||||||
</CLASSES>
|
|
||||||
<JAVADOC>
|
|
||||||
<root url="jar://$MAVEN_REPOSITORY$/commons-lang/commons-lang/2.6/commons-lang-2.6-javadoc.jar!/" />
|
|
||||||
</JAVADOC>
|
|
||||||
<SOURCES>
|
|
||||||
<root url="jar://$MAVEN_REPOSITORY$/commons-lang/commons-lang/2.6/commons-lang-2.6-sources.jar!/" />
|
|
||||||
</SOURCES>
|
|
||||||
</library>
|
|
||||||
</component>
|
|
|
@ -1,13 +0,0 @@
|
||||||
<component name="libraryTable">
|
|
||||||
<library name="Maven: junit:junit:3.8.1">
|
|
||||||
<CLASSES>
|
|
||||||
<root url="jar://$MAVEN_REPOSITORY$/junit/junit/3.8.1/junit-3.8.1.jar!/" />
|
|
||||||
</CLASSES>
|
|
||||||
<JAVADOC>
|
|
||||||
<root url="jar://$MAVEN_REPOSITORY$/junit/junit/3.8.1/junit-3.8.1-javadoc.jar!/" />
|
|
||||||
</JAVADOC>
|
|
||||||
<SOURCES>
|
|
||||||
<root url="jar://$MAVEN_REPOSITORY$/junit/junit/3.8.1/junit-3.8.1-sources.jar!/" />
|
|
||||||
</SOURCES>
|
|
||||||
</library>
|
|
||||||
</component>
|
|
|
@ -1,13 +0,0 @@
|
||||||
<component name="libraryTable">
|
|
||||||
<library name="Maven: net.bytebuddy:byte-buddy:1.6.11">
|
|
||||||
<CLASSES>
|
|
||||||
<root url="jar://$MAVEN_REPOSITORY$/net/bytebuddy/byte-buddy/1.6.11/byte-buddy-1.6.11.jar!/" />
|
|
||||||
</CLASSES>
|
|
||||||
<JAVADOC>
|
|
||||||
<root url="jar://$MAVEN_REPOSITORY$/net/bytebuddy/byte-buddy/1.6.11/byte-buddy-1.6.11-javadoc.jar!/" />
|
|
||||||
</JAVADOC>
|
|
||||||
<SOURCES>
|
|
||||||
<root url="jar://$MAVEN_REPOSITORY$/net/bytebuddy/byte-buddy/1.6.11/byte-buddy-1.6.11-sources.jar!/" />
|
|
||||||
</SOURCES>
|
|
||||||
</library>
|
|
||||||
</component>
|
|
|
@ -1,13 +0,0 @@
|
||||||
<component name="libraryTable">
|
|
||||||
<library name="Maven: net.bytebuddy:byte-buddy-agent:1.6.11">
|
|
||||||
<CLASSES>
|
|
||||||
<root url="jar://$MAVEN_REPOSITORY$/net/bytebuddy/byte-buddy-agent/1.6.11/byte-buddy-agent-1.6.11.jar!/" />
|
|
||||||
</CLASSES>
|
|
||||||
<JAVADOC>
|
|
||||||
<root url="jar://$MAVEN_REPOSITORY$/net/bytebuddy/byte-buddy-agent/1.6.11/byte-buddy-agent-1.6.11-javadoc.jar!/" />
|
|
||||||
</JAVADOC>
|
|
||||||
<SOURCES>
|
|
||||||
<root url="jar://$MAVEN_REPOSITORY$/net/bytebuddy/byte-buddy-agent/1.6.11/byte-buddy-agent-1.6.11-sources.jar!/" />
|
|
||||||
</SOURCES>
|
|
||||||
</library>
|
|
||||||
</component>
|
|
|
@ -1,13 +0,0 @@
|
||||||
<component name="libraryTable">
|
|
||||||
<library name="Maven: net.ess3:Essentials:2.13.1">
|
|
||||||
<CLASSES>
|
|
||||||
<root url="jar://$MAVEN_REPOSITORY$/net/ess3/Essentials/2.13.1/Essentials-2.13.1.jar!/" />
|
|
||||||
</CLASSES>
|
|
||||||
<JAVADOC>
|
|
||||||
<root url="jar://$MAVEN_REPOSITORY$/net/ess3/Essentials/2.13.1/Essentials-2.13.1-javadoc.jar!/" />
|
|
||||||
</JAVADOC>
|
|
||||||
<SOURCES>
|
|
||||||
<root url="jar://$MAVEN_REPOSITORY$/net/ess3/Essentials/2.13.1/Essentials-2.13.1-sources.jar!/" />
|
|
||||||
</SOURCES>
|
|
||||||
</library>
|
|
||||||
</component>
|
|
|
@ -1,13 +0,0 @@
|
||||||
<component name="libraryTable">
|
|
||||||
<library name="Maven: net.md-5:bungeecord-chat:1.12-SNAPSHOT">
|
|
||||||
<CLASSES>
|
|
||||||
<root url="jar://$MAVEN_REPOSITORY$/net/md-5/bungeecord-chat/1.12-SNAPSHOT/bungeecord-chat-1.12-20180712.114550-97.jar!/" />
|
|
||||||
</CLASSES>
|
|
||||||
<JAVADOC>
|
|
||||||
<root url="jar://$MAVEN_REPOSITORY$/net/md-5/bungeecord-chat/1.12-SNAPSHOT/bungeecord-chat-1.12-20180712.114550-97-javadoc.jar!/" />
|
|
||||||
</JAVADOC>
|
|
||||||
<SOURCES>
|
|
||||||
<root url="jar://$MAVEN_REPOSITORY$/net/md-5/bungeecord-chat/1.12-SNAPSHOT/bungeecord-chat-1.12-20180712.114550-97-sources.jar!/" />
|
|
||||||
</SOURCES>
|
|
||||||
</library>
|
|
||||||
</component>
|
|
|
@ -1,13 +0,0 @@
|
||||||
<component name="libraryTable">
|
|
||||||
<library name="Maven: org.bukkit:bukkit:1.13.1-R0.1-SNAPSHOT">
|
|
||||||
<CLASSES>
|
|
||||||
<root url="jar://$MAVEN_REPOSITORY$/org/bukkit/bukkit/1.13.1-R0.1-SNAPSHOT/bukkit-1.13.1-R0.1-20181022.190036-99.jar!/" />
|
|
||||||
</CLASSES>
|
|
||||||
<JAVADOC>
|
|
||||||
<root url="jar://$MAVEN_REPOSITORY$/org/bukkit/bukkit/1.13.1-R0.1-SNAPSHOT/bukkit-1.13.1-R0.1-20181022.190036-99-javadoc.jar!/" />
|
|
||||||
</JAVADOC>
|
|
||||||
<SOURCES>
|
|
||||||
<root url="jar://$MAVEN_REPOSITORY$/org/bukkit/bukkit/1.13.1-R0.1-SNAPSHOT/bukkit-1.13.1-R0.1-20181022.190036-99-sources.jar!/" />
|
|
||||||
</SOURCES>
|
|
||||||
</library>
|
|
||||||
</component>
|
|
|
@ -1,13 +0,0 @@
|
||||||
<component name="libraryTable">
|
|
||||||
<library name="Maven: org.javassist:javassist:3.20.0-GA">
|
|
||||||
<CLASSES>
|
|
||||||
<root url="jar://$MAVEN_REPOSITORY$/org/javassist/javassist/3.20.0-GA/javassist-3.20.0-GA.jar!/" />
|
|
||||||
</CLASSES>
|
|
||||||
<JAVADOC>
|
|
||||||
<root url="jar://$MAVEN_REPOSITORY$/org/javassist/javassist/3.20.0-GA/javassist-3.20.0-GA-javadoc.jar!/" />
|
|
||||||
</JAVADOC>
|
|
||||||
<SOURCES>
|
|
||||||
<root url="jar://$MAVEN_REPOSITORY$/org/javassist/javassist/3.20.0-GA/javassist-3.20.0-GA-sources.jar!/" />
|
|
||||||
</SOURCES>
|
|
||||||
</library>
|
|
||||||
</component>
|
|
|
@ -1,13 +0,0 @@
|
||||||
<component name="libraryTable">
|
|
||||||
<library name="Maven: org.mockito:mockito-core:2.7.20">
|
|
||||||
<CLASSES>
|
|
||||||
<root url="jar://$MAVEN_REPOSITORY$/org/mockito/mockito-core/2.7.20/mockito-core-2.7.20.jar!/" />
|
|
||||||
</CLASSES>
|
|
||||||
<JAVADOC>
|
|
||||||
<root url="jar://$MAVEN_REPOSITORY$/org/mockito/mockito-core/2.7.20/mockito-core-2.7.20-javadoc.jar!/" />
|
|
||||||
</JAVADOC>
|
|
||||||
<SOURCES>
|
|
||||||
<root url="jar://$MAVEN_REPOSITORY$/org/mockito/mockito-core/2.7.20/mockito-core-2.7.20-sources.jar!/" />
|
|
||||||
</SOURCES>
|
|
||||||
</library>
|
|
||||||
</component>
|
|
|
@ -1,13 +0,0 @@
|
||||||
<component name="libraryTable">
|
|
||||||
<library name="Maven: org.objenesis:objenesis:2.5">
|
|
||||||
<CLASSES>
|
|
||||||
<root url="jar://$MAVEN_REPOSITORY$/org/objenesis/objenesis/2.5/objenesis-2.5.jar!/" />
|
|
||||||
</CLASSES>
|
|
||||||
<JAVADOC>
|
|
||||||
<root url="jar://$MAVEN_REPOSITORY$/org/objenesis/objenesis/2.5/objenesis-2.5-javadoc.jar!/" />
|
|
||||||
</JAVADOC>
|
|
||||||
<SOURCES>
|
|
||||||
<root url="jar://$MAVEN_REPOSITORY$/org/objenesis/objenesis/2.5/objenesis-2.5-sources.jar!/" />
|
|
||||||
</SOURCES>
|
|
||||||
</library>
|
|
||||||
</component>
|
|
|
@ -1,14 +0,0 @@
|
||||||
<component name="libraryTable">
|
|
||||||
<library name="Maven: org.projectlombok:lombok:1.16.16">
|
|
||||||
<CLASSES>
|
|
||||||
<root url="jar://$MAVEN_REPOSITORY$/org/projectlombok/lombok/1.16.16/lombok-1.16.16.jar!/" />
|
|
||||||
</CLASSES>
|
|
||||||
<JAVADOC>
|
|
||||||
<root url="jar://$MAVEN_REPOSITORY$/org/projectlombok/lombok/1.16.16/lombok-1.16.16-javadoc.jar!/" />
|
|
||||||
</JAVADOC>
|
|
||||||
<SOURCES>
|
|
||||||
<root url="jar://$MAVEN_REPOSITORY$/org/projectlombok/lombok/1.16.16/lombok-1.16.16-sources.jar!/" />
|
|
||||||
<root url="jar://$USER_HOME$/.ideaLibSources/lombok-1.16.16-sources.jar!/" />
|
|
||||||
</SOURCES>
|
|
||||||
</library>
|
|
||||||
</component>
|
|
|
@ -1,13 +0,0 @@
|
||||||
<component name="libraryTable">
|
|
||||||
<library name="Maven: org.reflections:reflections:0.9.10">
|
|
||||||
<CLASSES>
|
|
||||||
<root url="jar://$MAVEN_REPOSITORY$/org/reflections/reflections/0.9.10/reflections-0.9.10.jar!/" />
|
|
||||||
</CLASSES>
|
|
||||||
<JAVADOC>
|
|
||||||
<root url="jar://$MAVEN_REPOSITORY$/org/reflections/reflections/0.9.10/reflections-0.9.10-javadoc.jar!/" />
|
|
||||||
</JAVADOC>
|
|
||||||
<SOURCES>
|
|
||||||
<root url="jar://$MAVEN_REPOSITORY$/org/reflections/reflections/0.9.10/reflections-0.9.10-sources.jar!/" />
|
|
||||||
</SOURCES>
|
|
||||||
</library>
|
|
||||||
</component>
|
|
|
@ -1,13 +0,0 @@
|
||||||
<component name="libraryTable">
|
|
||||||
<library name="Maven: org.spigotmc:spigot-api:1.12.2-R0.1-SNAPSHOT">
|
|
||||||
<CLASSES>
|
|
||||||
<root url="jar://$MAVEN_REPOSITORY$/org/spigotmc/spigot-api/1.12.2-R0.1-SNAPSHOT/spigot-api-1.12.2-R0.1-SNAPSHOT.jar!/" />
|
|
||||||
</CLASSES>
|
|
||||||
<JAVADOC>
|
|
||||||
<root url="jar://$MAVEN_REPOSITORY$/org/spigotmc/spigot-api/1.12.2-R0.1-SNAPSHOT/spigot-api-1.12.2-R0.1-SNAPSHOT-javadoc.jar!/" />
|
|
||||||
</JAVADOC>
|
|
||||||
<SOURCES>
|
|
||||||
<root url="jar://$MAVEN_REPOSITORY$/org/spigotmc/spigot-api/1.12.2-R0.1-SNAPSHOT/spigot-api-1.12.2-R0.1-SNAPSHOT-sources.jar!/" />
|
|
||||||
</SOURCES>
|
|
||||||
</library>
|
|
||||||
</component>
|
|
|
@ -1,13 +0,0 @@
|
||||||
<component name="libraryTable">
|
|
||||||
<library name="Maven: org.yaml:snakeyaml:1.19">
|
|
||||||
<CLASSES>
|
|
||||||
<root url="jar://$MAVEN_REPOSITORY$/org/yaml/snakeyaml/1.19/snakeyaml-1.19.jar!/" />
|
|
||||||
</CLASSES>
|
|
||||||
<JAVADOC>
|
|
||||||
<root url="jar://$MAVEN_REPOSITORY$/org/yaml/snakeyaml/1.19/snakeyaml-1.19-javadoc.jar!/" />
|
|
||||||
</JAVADOC>
|
|
||||||
<SOURCES>
|
|
||||||
<root url="jar://$MAVEN_REPOSITORY$/org/yaml/snakeyaml/1.19/snakeyaml-1.19-sources.jar!/" />
|
|
||||||
</SOURCES>
|
|
||||||
</library>
|
|
||||||
</component>
|
|
|
@ -1,8 +0,0 @@
|
||||||
<?xml version="1.0" encoding="UTF-8"?>
|
|
||||||
<project version="4">
|
|
||||||
<component name="MarkdownExportedFiles">
|
|
||||||
<htmlFiles />
|
|
||||||
<imageFiles />
|
|
||||||
<otherFiles />
|
|
||||||
</component>
|
|
||||||
</project>
|
|
|
@ -1,82 +0,0 @@
|
||||||
<?xml version="1.0" encoding="UTF-8"?>
|
|
||||||
<project version="4">
|
|
||||||
<component name="MarkdownProjectSettings" wasCopied="false">
|
|
||||||
<PreviewSettings splitEditorLayout="SPLIT" splitEditorPreview="PREVIEW" useGrayscaleRendering="false" zoomFactor="1.0" maxImageWidth="0" showGitHubPageIfSynced="false" allowBrowsingInPreview="false" synchronizePreviewPosition="true" highlightPreviewType="NONE" highlightFadeOut="5" highlightOnTyping="true" synchronizeSourcePosition="true" verticallyAlignSourceAndPreviewSyncPosition="true" showSearchHighlightsInPreview="false" showSelectionInPreview="true" openRemoteLinks="true" replaceUnicodeEmoji="false" lastLayoutSetsDefault="false">
|
|
||||||
<PanelProvider>
|
|
||||||
<provider providerId="com.vladsch.idea.multimarkdown.editor.swing.html.panel" providerName="Default - Swing" />
|
|
||||||
</PanelProvider>
|
|
||||||
</PreviewSettings>
|
|
||||||
<ParserSettings gitHubSyntaxChange="false" emojiShortcuts="1" emojiImages="0">
|
|
||||||
<PegdownExtensions>
|
|
||||||
<option name="ABBREVIATIONS" value="false" />
|
|
||||||
<option name="ANCHORLINKS" value="true" />
|
|
||||||
<option name="ASIDE" value="false" />
|
|
||||||
<option name="ATXHEADERSPACE" value="true" />
|
|
||||||
<option name="AUTOLINKS" value="true" />
|
|
||||||
<option name="DEFINITIONS" value="false" />
|
|
||||||
<option name="DEFINITION_BREAK_DOUBLE_BLANK_LINE" value="false" />
|
|
||||||
<option name="FENCED_CODE_BLOCKS" value="true" />
|
|
||||||
<option name="FOOTNOTES" value="false" />
|
|
||||||
<option name="HARDWRAPS" value="false" />
|
|
||||||
<option name="HTML_DEEP_PARSER" value="false" />
|
|
||||||
<option name="INSERTED" value="false" />
|
|
||||||
<option name="QUOTES" value="false" />
|
|
||||||
<option name="RELAXEDHRULES" value="true" />
|
|
||||||
<option name="SMARTS" value="false" />
|
|
||||||
<option name="STRIKETHROUGH" value="true" />
|
|
||||||
<option name="SUBSCRIPT" value="false" />
|
|
||||||
<option name="SUPERSCRIPT" value="false" />
|
|
||||||
<option name="SUPPRESS_HTML_BLOCKS" value="false" />
|
|
||||||
<option name="SUPPRESS_INLINE_HTML" value="false" />
|
|
||||||
<option name="TABLES" value="true" />
|
|
||||||
<option name="TASKLISTITEMS" value="true" />
|
|
||||||
<option name="TOC" value="false" />
|
|
||||||
<option name="WIKILINKS" value="true" />
|
|
||||||
</PegdownExtensions>
|
|
||||||
<ParserOptions>
|
|
||||||
<option name="ADMONITION_EXT" value="false" />
|
|
||||||
<option name="ATTRIBUTES_EXT" value="false" />
|
|
||||||
<option name="COMMONMARK_LISTS" value="true" />
|
|
||||||
<option name="DUMMY" value="false" />
|
|
||||||
<option name="EMOJI_SHORTCUTS" value="true" />
|
|
||||||
<option name="ENUMERATED_REFERENCES_EXT" value="false" />
|
|
||||||
<option name="FLEXMARK_FRONT_MATTER" value="false" />
|
|
||||||
<option name="GFM_LOOSE_BLANK_LINE_AFTER_ITEM_PARA" value="false" />
|
|
||||||
<option name="GFM_TABLE_RENDERING" value="true" />
|
|
||||||
<option name="GITBOOK_URL_ENCODING" value="false" />
|
|
||||||
<option name="GITHUB_LISTS" value="false" />
|
|
||||||
<option name="GITHUB_WIKI_LINKS" value="true" />
|
|
||||||
<option name="GITLAB_EXT" value="false" />
|
|
||||||
<option name="GITLAB_MATH_EXT" value="false" />
|
|
||||||
<option name="GITLAB_MERMAID_EXT" value="false" />
|
|
||||||
<option name="HEADER_ID_NO_DUPED_DASHES" value="false" />
|
|
||||||
<option name="JEKYLL_FRONT_MATTER" value="false" />
|
|
||||||
<option name="MACROS_EXT" value="false" />
|
|
||||||
<option name="NO_TEXT_ATTRIBUTES" value="false" />
|
|
||||||
<option name="PARSE_HTML_ANCHOR_ID" value="false" />
|
|
||||||
<option name="SIM_TOC_BLANK_LINE_SPACER" value="true" />
|
|
||||||
</ParserOptions>
|
|
||||||
</ParserSettings>
|
|
||||||
<HtmlSettings headerTopEnabled="false" headerBottomEnabled="false" bodyTopEnabled="false" bodyBottomEnabled="false" embedUrlContent="false" addPageHeader="true" embedImages="false" embedHttpImages="false" imageUriSerials="false" addDocTypeHtml="true">
|
|
||||||
<GeneratorProvider>
|
|
||||||
<provider providerId="com.vladsch.idea.multimarkdown.editor.swing.html.generator" providerName="Default Swing HTML Generator" />
|
|
||||||
</GeneratorProvider>
|
|
||||||
<headerTop />
|
|
||||||
<headerBottom />
|
|
||||||
<bodyTop />
|
|
||||||
<bodyBottom />
|
|
||||||
</HtmlSettings>
|
|
||||||
<CssSettings previewScheme="UI_SCHEME" cssUri="" isCssUriEnabled="false" isCssUriSerial="false" isCssTextEnabled="false" isDynamicPageWidth="true">
|
|
||||||
<StylesheetProvider>
|
|
||||||
<provider providerId="com.vladsch.idea.multimarkdown.editor.swing.html.css" providerName="Default Swing Stylesheet" />
|
|
||||||
</StylesheetProvider>
|
|
||||||
<ScriptProviders />
|
|
||||||
<cssText />
|
|
||||||
<cssUriHistory />
|
|
||||||
</CssSettings>
|
|
||||||
<HtmlExportSettings updateOnSave="false" parentDir="" targetDir="" cssDir="" scriptDir="" plainHtml="false" imageDir="" copyLinkedImages="false" imageUniquifyType="0" targetExt="" useTargetExt="false" noCssNoScripts="false" linkToExportedHtml="true" exportOnSettingsChange="true" regenerateOnProjectOpen="false" linkFormatType="HTTP_ABSOLUTE" />
|
|
||||||
<LinkMapSettings>
|
|
||||||
<textMaps />
|
|
||||||
</LinkMapSettings>
|
|
||||||
</component>
|
|
||||||
</project>
|
|
|
@ -1,3 +0,0 @@
|
||||||
<component name="MarkdownNavigator.ProfileManager">
|
|
||||||
<settings default="" pdf-export="" />
|
|
||||||
</component>
|
|
|
@ -1,23 +0,0 @@
|
||||||
<?xml version="1.0" encoding="UTF-8"?>
|
|
||||||
<project version="4">
|
|
||||||
<component name="EntryPointsManager">
|
|
||||||
<list size="1">
|
|
||||||
<item index="0" class="java.lang.String" itemvalue="org.bukkit.event.EventHandler" />
|
|
||||||
</list>
|
|
||||||
</component>
|
|
||||||
<component name="MavenProjectsManager">
|
|
||||||
<option name="originalFiles">
|
|
||||||
<list>
|
|
||||||
<option value="$PROJECT_DIR$/pom.xml" />
|
|
||||||
</list>
|
|
||||||
</option>
|
|
||||||
<option name="ignoredFiles">
|
|
||||||
<set>
|
|
||||||
<option value="$PROJECT_DIR$/pom.xml" />
|
|
||||||
</set>
|
|
||||||
</option>
|
|
||||||
</component>
|
|
||||||
<component name="ProjectRootManager" version="2" project-jdk-name="1.8" project-jdk-type="JavaSDK">
|
|
||||||
<output url="file://$PROJECT_DIR$/out" />
|
|
||||||
</component>
|
|
||||||
</project>
|
|
|
@ -1,10 +0,0 @@
|
||||||
<?xml version="1.0" encoding="UTF-8"?>
|
|
||||||
<project version="4">
|
|
||||||
<component name="ProjectModuleManager">
|
|
||||||
<modules>
|
|
||||||
<module fileurl="file://$PROJECT_DIR$/BuildConfigUpdater/BuildConfigUpdater.iml" filepath="$PROJECT_DIR$/BuildConfigUpdater/BuildConfigUpdater.iml" />
|
|
||||||
<module fileurl="file://$PROJECT_DIR$/ButtonCore/ButtonCore (1) (com.github.TBMCPlugins.ButtonCore).iml" filepath="$PROJECT_DIR$/ButtonCore/ButtonCore (1) (com.github.TBMCPlugins.ButtonCore).iml" />
|
|
||||||
<module fileurl="file://$PROJECT_DIR$/ButtonProcessor/ButtonProcessor.iml" filepath="$PROJECT_DIR$/ButtonProcessor/ButtonProcessor.iml" />
|
|
||||||
</modules>
|
|
||||||
</component>
|
|
||||||
</project>
|
|
|
@ -1,124 +0,0 @@
|
||||||
<?xml version="1.0" encoding="UTF-8"?>
|
|
||||||
<project version="4">
|
|
||||||
<component name="Palette2">
|
|
||||||
<group name="Swing">
|
|
||||||
<item class="com.intellij.uiDesigner.HSpacer" tooltip-text="Horizontal Spacer" icon="/com/intellij/uiDesigner/icons/hspacer.png" removable="false" auto-create-binding="false" can-attach-label="false">
|
|
||||||
<default-constraints vsize-policy="1" hsize-policy="6" anchor="0" fill="1" />
|
|
||||||
</item>
|
|
||||||
<item class="com.intellij.uiDesigner.VSpacer" tooltip-text="Vertical Spacer" icon="/com/intellij/uiDesigner/icons/vspacer.png" removable="false" auto-create-binding="false" can-attach-label="false">
|
|
||||||
<default-constraints vsize-policy="6" hsize-policy="1" anchor="0" fill="2" />
|
|
||||||
</item>
|
|
||||||
<item class="javax.swing.JPanel" icon="/com/intellij/uiDesigner/icons/panel.png" removable="false" auto-create-binding="false" can-attach-label="false">
|
|
||||||
<default-constraints vsize-policy="3" hsize-policy="3" anchor="0" fill="3" />
|
|
||||||
</item>
|
|
||||||
<item class="javax.swing.JScrollPane" icon="/com/intellij/uiDesigner/icons/scrollPane.png" removable="false" auto-create-binding="false" can-attach-label="true">
|
|
||||||
<default-constraints vsize-policy="7" hsize-policy="7" anchor="0" fill="3" />
|
|
||||||
</item>
|
|
||||||
<item class="javax.swing.JButton" icon="/com/intellij/uiDesigner/icons/button.png" removable="false" auto-create-binding="true" can-attach-label="false">
|
|
||||||
<default-constraints vsize-policy="0" hsize-policy="3" anchor="0" fill="1" />
|
|
||||||
<initial-values>
|
|
||||||
<property name="text" value="Button" />
|
|
||||||
</initial-values>
|
|
||||||
</item>
|
|
||||||
<item class="javax.swing.JRadioButton" icon="/com/intellij/uiDesigner/icons/radioButton.png" removable="false" auto-create-binding="true" can-attach-label="false">
|
|
||||||
<default-constraints vsize-policy="0" hsize-policy="3" anchor="8" fill="0" />
|
|
||||||
<initial-values>
|
|
||||||
<property name="text" value="RadioButton" />
|
|
||||||
</initial-values>
|
|
||||||
</item>
|
|
||||||
<item class="javax.swing.JCheckBox" icon="/com/intellij/uiDesigner/icons/checkBox.png" removable="false" auto-create-binding="true" can-attach-label="false">
|
|
||||||
<default-constraints vsize-policy="0" hsize-policy="3" anchor="8" fill="0" />
|
|
||||||
<initial-values>
|
|
||||||
<property name="text" value="CheckBox" />
|
|
||||||
</initial-values>
|
|
||||||
</item>
|
|
||||||
<item class="javax.swing.JLabel" icon="/com/intellij/uiDesigner/icons/label.png" removable="false" auto-create-binding="false" can-attach-label="false">
|
|
||||||
<default-constraints vsize-policy="0" hsize-policy="0" anchor="8" fill="0" />
|
|
||||||
<initial-values>
|
|
||||||
<property name="text" value="Label" />
|
|
||||||
</initial-values>
|
|
||||||
</item>
|
|
||||||
<item class="javax.swing.JTextField" icon="/com/intellij/uiDesigner/icons/textField.png" removable="false" auto-create-binding="true" can-attach-label="true">
|
|
||||||
<default-constraints vsize-policy="0" hsize-policy="6" anchor="8" fill="1">
|
|
||||||
<preferred-size width="150" height="-1" />
|
|
||||||
</default-constraints>
|
|
||||||
</item>
|
|
||||||
<item class="javax.swing.JPasswordField" icon="/com/intellij/uiDesigner/icons/passwordField.png" removable="false" auto-create-binding="true" can-attach-label="true">
|
|
||||||
<default-constraints vsize-policy="0" hsize-policy="6" anchor="8" fill="1">
|
|
||||||
<preferred-size width="150" height="-1" />
|
|
||||||
</default-constraints>
|
|
||||||
</item>
|
|
||||||
<item class="javax.swing.JFormattedTextField" icon="/com/intellij/uiDesigner/icons/formattedTextField.png" removable="false" auto-create-binding="true" can-attach-label="true">
|
|
||||||
<default-constraints vsize-policy="0" hsize-policy="6" anchor="8" fill="1">
|
|
||||||
<preferred-size width="150" height="-1" />
|
|
||||||
</default-constraints>
|
|
||||||
</item>
|
|
||||||
<item class="javax.swing.JTextArea" icon="/com/intellij/uiDesigner/icons/textArea.png" removable="false" auto-create-binding="true" can-attach-label="true">
|
|
||||||
<default-constraints vsize-policy="6" hsize-policy="6" anchor="0" fill="3">
|
|
||||||
<preferred-size width="150" height="50" />
|
|
||||||
</default-constraints>
|
|
||||||
</item>
|
|
||||||
<item class="javax.swing.JTextPane" icon="/com/intellij/uiDesigner/icons/textPane.png" removable="false" auto-create-binding="true" can-attach-label="true">
|
|
||||||
<default-constraints vsize-policy="6" hsize-policy="6" anchor="0" fill="3">
|
|
||||||
<preferred-size width="150" height="50" />
|
|
||||||
</default-constraints>
|
|
||||||
</item>
|
|
||||||
<item class="javax.swing.JEditorPane" icon="/com/intellij/uiDesigner/icons/editorPane.png" removable="false" auto-create-binding="true" can-attach-label="true">
|
|
||||||
<default-constraints vsize-policy="6" hsize-policy="6" anchor="0" fill="3">
|
|
||||||
<preferred-size width="150" height="50" />
|
|
||||||
</default-constraints>
|
|
||||||
</item>
|
|
||||||
<item class="javax.swing.JComboBox" icon="/com/intellij/uiDesigner/icons/comboBox.png" removable="false" auto-create-binding="true" can-attach-label="true">
|
|
||||||
<default-constraints vsize-policy="0" hsize-policy="2" anchor="8" fill="1" />
|
|
||||||
</item>
|
|
||||||
<item class="javax.swing.JTable" icon="/com/intellij/uiDesigner/icons/table.png" removable="false" auto-create-binding="true" can-attach-label="false">
|
|
||||||
<default-constraints vsize-policy="6" hsize-policy="6" anchor="0" fill="3">
|
|
||||||
<preferred-size width="150" height="50" />
|
|
||||||
</default-constraints>
|
|
||||||
</item>
|
|
||||||
<item class="javax.swing.JList" icon="/com/intellij/uiDesigner/icons/list.png" removable="false" auto-create-binding="true" can-attach-label="false">
|
|
||||||
<default-constraints vsize-policy="6" hsize-policy="2" anchor="0" fill="3">
|
|
||||||
<preferred-size width="150" height="50" />
|
|
||||||
</default-constraints>
|
|
||||||
</item>
|
|
||||||
<item class="javax.swing.JTree" icon="/com/intellij/uiDesigner/icons/tree.png" removable="false" auto-create-binding="true" can-attach-label="false">
|
|
||||||
<default-constraints vsize-policy="6" hsize-policy="6" anchor="0" fill="3">
|
|
||||||
<preferred-size width="150" height="50" />
|
|
||||||
</default-constraints>
|
|
||||||
</item>
|
|
||||||
<item class="javax.swing.JTabbedPane" icon="/com/intellij/uiDesigner/icons/tabbedPane.png" removable="false" auto-create-binding="true" can-attach-label="false">
|
|
||||||
<default-constraints vsize-policy="3" hsize-policy="3" anchor="0" fill="3">
|
|
||||||
<preferred-size width="200" height="200" />
|
|
||||||
</default-constraints>
|
|
||||||
</item>
|
|
||||||
<item class="javax.swing.JSplitPane" icon="/com/intellij/uiDesigner/icons/splitPane.png" removable="false" auto-create-binding="false" can-attach-label="false">
|
|
||||||
<default-constraints vsize-policy="3" hsize-policy="3" anchor="0" fill="3">
|
|
||||||
<preferred-size width="200" height="200" />
|
|
||||||
</default-constraints>
|
|
||||||
</item>
|
|
||||||
<item class="javax.swing.JSpinner" icon="/com/intellij/uiDesigner/icons/spinner.png" removable="false" auto-create-binding="true" can-attach-label="true">
|
|
||||||
<default-constraints vsize-policy="0" hsize-policy="6" anchor="8" fill="1" />
|
|
||||||
</item>
|
|
||||||
<item class="javax.swing.JSlider" icon="/com/intellij/uiDesigner/icons/slider.png" removable="false" auto-create-binding="true" can-attach-label="false">
|
|
||||||
<default-constraints vsize-policy="0" hsize-policy="6" anchor="8" fill="1" />
|
|
||||||
</item>
|
|
||||||
<item class="javax.swing.JSeparator" icon="/com/intellij/uiDesigner/icons/separator.png" removable="false" auto-create-binding="false" can-attach-label="false">
|
|
||||||
<default-constraints vsize-policy="6" hsize-policy="6" anchor="0" fill="3" />
|
|
||||||
</item>
|
|
||||||
<item class="javax.swing.JProgressBar" icon="/com/intellij/uiDesigner/icons/progressbar.png" removable="false" auto-create-binding="true" can-attach-label="false">
|
|
||||||
<default-constraints vsize-policy="0" hsize-policy="6" anchor="0" fill="1" />
|
|
||||||
</item>
|
|
||||||
<item class="javax.swing.JToolBar" icon="/com/intellij/uiDesigner/icons/toolbar.png" removable="false" auto-create-binding="false" can-attach-label="false">
|
|
||||||
<default-constraints vsize-policy="0" hsize-policy="6" anchor="0" fill="1">
|
|
||||||
<preferred-size width="-1" height="20" />
|
|
||||||
</default-constraints>
|
|
||||||
</item>
|
|
||||||
<item class="javax.swing.JToolBar$Separator" icon="/com/intellij/uiDesigner/icons/toolbarSeparator.png" removable="false" auto-create-binding="false" can-attach-label="false">
|
|
||||||
<default-constraints vsize-policy="0" hsize-policy="0" anchor="0" fill="1" />
|
|
||||||
</item>
|
|
||||||
<item class="javax.swing.JScrollBar" icon="/com/intellij/uiDesigner/icons/scrollbar.png" removable="false" auto-create-binding="true" can-attach-label="false">
|
|
||||||
<default-constraints vsize-policy="6" hsize-policy="0" anchor="0" fill="2" />
|
|
||||||
</item>
|
|
||||||
</group>
|
|
||||||
</component>
|
|
||||||
</project>
|
|
|
@ -1,6 +0,0 @@
|
||||||
<?xml version="1.0" encoding="UTF-8"?>
|
|
||||||
<project version="4">
|
|
||||||
<component name="VcsDirectoryMappings">
|
|
||||||
<mapping directory="" vcs="Git" />
|
|
||||||
</component>
|
|
||||||
</project>
|
|
17
.travis.yml
17
.travis.yml
|
@ -9,18 +9,13 @@ before_install: | # Wget BuildTools and run if cached folder not found
|
||||||
fi
|
fi
|
||||||
language: java
|
language: java
|
||||||
jdk:
|
jdk:
|
||||||
- oraclejdk8
|
- oraclejdk11
|
||||||
sudo: true
|
sudo: true
|
||||||
deploy:
|
deploy:
|
||||||
# deploy develop to the staging environment
|
- provider: releases
|
||||||
- provider: script
|
api_key:
|
||||||
script: chmod +x deploy.sh && sh deploy.sh staging
|
secure: "T/ITeRn4JSx4HS4n44P7vy03HWmJGVpYeR6tABu8qOLrwz2MUCFu8xvYqoq4MiqIKqFIKtZHgCSWiB1WsTIJPHm9S2xYs0BFocoQDthE+eCtT2wgCHj/xdo0wBm8uktXr2hxRF5Nd2R/mfSLkoVxAM6otOoSa1SidRGKgDCJxRnsgssk5igQR+tpahZYPvuzM5xJ4G6J07cC+HHM7RLYXkkKrsK3LFugTsnNtctwmxQkm6SqzDcc8YPwoJGhj8PLbXc5S8/KaWT0//LNdypnzeIaRv+aY+ky/zLntXlw3EFOk4erTthAEMSu2x6PgX5B/paMawdwnqKul/L4ynMGojrLH8ha9KM7p/lze2bxCaf08RFVFvTQt6yzmvM1suL4KH6gAF4mKhyaU0kBeOsnTTskoxyGxvbZgdo0Y1V+Yd7w58eu8zfxnauaX7f2DEz7gH4qkSl+hC7HAFoY7m7IXkgVN6Vuv3lGdFO5S15lbGoihOPqt9T79lBxi/efiXEE4BmA1g8MeLsyN8N/EO+LqVr6xXAKJet6YtOAe/iIAqxpNDSuME1szusc6+4q3jOy6cPmB1TKsfnIKQmbT98SHc9wE4/76VLd2PlNPppa0AIG/g+qnjhjpFQxB7LnWdP+D6io9N1FYrvoOX8UVAp4XYhwUMNLUInDT/6P6j8lL7A="
|
||||||
|
file: 'Chroma-Core/target/Chroma-Core.jar'
|
||||||
on:
|
on:
|
||||||
branch: dev
|
tags: true
|
||||||
skip_cleanup: true
|
|
||||||
# deploy master to production
|
|
||||||
- provider: script
|
|
||||||
script: chmod +x deploy.sh && sh deploy.sh production
|
|
||||||
on:
|
|
||||||
branch: master
|
|
||||||
skip_cleanup: true
|
skip_cleanup: true
|
||||||
|
|
|
@ -1,40 +0,0 @@
|
||||||
<?xml version="1.0" encoding="UTF-8"?>
|
|
||||||
<module org.jetbrains.idea.maven.project.MavenProjectsManager.isMavenModule="true" type="JAVA_MODULE" version="4">
|
|
||||||
<component name="NewModuleRootManager" LANGUAGE_LEVEL="JDK_1_8">
|
|
||||||
<output url="file://$MODULE_DIR$/target/classes" />
|
|
||||||
<output-test url="file://$MODULE_DIR$/target/test-classes" />
|
|
||||||
<content url="file://$MODULE_DIR$">
|
|
||||||
<sourceFolder url="file://$MODULE_DIR$/src/main/java" isTestSource="false" />
|
|
||||||
<sourceFolder url="file://$MODULE_DIR$/src/main/resources" type="java-resource" />
|
|
||||||
<sourceFolder url="file://$MODULE_DIR$/src/test/java" isTestSource="true" />
|
|
||||||
<excludeFolder url="file://$MODULE_DIR$/target" />
|
|
||||||
</content>
|
|
||||||
<orderEntry type="inheritedJdk" />
|
|
||||||
<orderEntry type="sourceFolder" forTests="false" />
|
|
||||||
<orderEntry type="module" module-name="ButtonCore (1) (com.github.TBMCPlugins.ButtonCore)" />
|
|
||||||
<orderEntry type="module" module-name="ButtonCore (1) (com.github.TBMCPlugins.ButtonCore)" />
|
|
||||||
<orderEntry type="module" module-name="ButtonCore (1) (com.github.TBMCPlugins.ButtonCore)" />
|
|
||||||
<orderEntry type="module" module-name="ButtonCore (1) (com.github.TBMCPlugins.ButtonCore)" />
|
|
||||||
<orderEntry type="module" module-name="ButtonCore (1) (com.github.TBMCPlugins.ButtonCore)" />
|
|
||||||
<orderEntry type="module" module-name="ButtonCore (1) (com.github.TBMCPlugins.ButtonCore)" />
|
|
||||||
<orderEntry type="module" module-name="ButtonCore (1) (com.github.TBMCPlugins.ButtonCore)" />
|
|
||||||
<orderEntry type="module" module-name="ButtonCore (1) (com.github.TBMCPlugins.ButtonCore)" />
|
|
||||||
<orderEntry type="library" name="Maven: org.reflections:reflections:0.9.10" level="project" />
|
|
||||||
<orderEntry type="library" name="Maven: com.google.code.findbugs:annotations:2.0.1" level="project" />
|
|
||||||
<orderEntry type="library" name="Maven: org.javassist:javassist:3.20.0-GA" level="project" />
|
|
||||||
<orderEntry type="library" name="Maven: org.mockito:mockito-core:2.7.20" level="project" />
|
|
||||||
<orderEntry type="library" scope="RUNTIME" name="Maven: net.bytebuddy:byte-buddy:1.6.11" level="project" />
|
|
||||||
<orderEntry type="library" scope="RUNTIME" name="Maven: net.bytebuddy:byte-buddy-agent:1.6.11" level="project" />
|
|
||||||
<orderEntry type="library" scope="RUNTIME" name="Maven: org.objenesis:objenesis:2.5" level="project" />
|
|
||||||
<orderEntry type="module" module-name="ButtonProcessor" />
|
|
||||||
<orderEntry type="library" name="Maven: org.spigotmc:spigot-api:1.12.2-R0.1-SNAPSHOT" level="project" />
|
|
||||||
<orderEntry type="library" name="Maven: commons-lang:commons-lang:2.6" level="project" />
|
|
||||||
<orderEntry type="library" name="Maven: com.googlecode.json-simple:json-simple:1.1.1" level="project" />
|
|
||||||
<orderEntry type="library" name="Maven: com.google.guava:guava:21.0" level="project" />
|
|
||||||
<orderEntry type="library" name="Maven: com.google.code.gson:gson:2.8.0" level="project" />
|
|
||||||
<orderEntry type="library" name="Maven: org.yaml:snakeyaml:1.19" level="project" />
|
|
||||||
<orderEntry type="library" name="Maven: net.md-5:bungeecord-chat:1.12-SNAPSHOT" level="project" />
|
|
||||||
<orderEntry type="library" name="Maven: commons-io:commons-io:2.6" level="project" />
|
|
||||||
<orderEntry type="library" scope="TEST" name="Maven: junit:junit:3.8.1" level="project" />
|
|
||||||
</component>
|
|
||||||
</module>
|
|
|
@ -1,43 +0,0 @@
|
||||||
<?xml version="1.0" encoding="UTF-8"?>
|
|
||||||
<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">
|
|
||||||
<parent>
|
|
||||||
<artifactId>ButtonCore</artifactId>
|
|
||||||
<groupId>com.github.TBMCPlugins</groupId>
|
|
||||||
<version>master-SNAPSHOT</version>
|
|
||||||
</parent>
|
|
||||||
<modelVersion>4.0.0</modelVersion>
|
|
||||||
|
|
||||||
<artifactId>BuildConfigUpdater</artifactId>
|
|
||||||
|
|
||||||
<repositories>
|
|
||||||
<repository>
|
|
||||||
<id>Jitpack</id>
|
|
||||||
<url>https://jitpack.io/</url>
|
|
||||||
</repository>
|
|
||||||
<repository>
|
|
||||||
<id>spigot-repo</id>
|
|
||||||
<url>https://hub.spigotmc.org/nexus/content/repositories/snapshots/</url>
|
|
||||||
</repository>
|
|
||||||
</repositories>
|
|
||||||
|
|
||||||
<dependencies>
|
|
||||||
<dependency>
|
|
||||||
<groupId>com.github.TBMCPlugins.ButtonCore</groupId>
|
|
||||||
<artifactId>ButtonCore</artifactId>
|
|
||||||
<version>master-SNAPSHOT</version>
|
|
||||||
</dependency>
|
|
||||||
<dependency> <!-- Needed for TBMCCoreAPI -->
|
|
||||||
<groupId>org.spigotmc</groupId>
|
|
||||||
<artifactId>spigot-api</artifactId>
|
|
||||||
<version>1.12.2-R0.1-SNAPSHOT</version>
|
|
||||||
</dependency>
|
|
||||||
<dependency>
|
|
||||||
<groupId>commons-io</groupId>
|
|
||||||
<artifactId>commons-io</artifactId>
|
|
||||||
<version>2.6</version>
|
|
||||||
</dependency>
|
|
||||||
</dependencies>
|
|
||||||
|
|
||||||
</project>
|
|
|
@ -1,16 +0,0 @@
|
||||||
import buttondevteam.core.component.updater.PluginUpdater;
|
|
||||||
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.stream.Collectors;
|
|
||||||
|
|
||||||
public class BCUMain {
|
|
||||||
public static void main(String[] args) {
|
|
||||||
System.out.println("Getting list of repositories...");
|
|
||||||
List<String> plugins = PluginUpdater.GetPluginNames();
|
|
||||||
System.out.println("Removing non-Maven projects...");
|
|
||||||
plugins.removeIf(plugin -> PluginUpdater.isNotMaven(plugin, "master"));
|
|
||||||
System.out.println(plugins.stream().collect(Collectors.joining("\n")));
|
|
||||||
for (String plugin : plugins) { //TODO: We don't want to apply it all at once, especially to unused/unowned repos
|
|
||||||
} //TODO: Add it to ButtonCore - or actually as a plugin or ButtonProcessor
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,2 +0,0 @@
|
||||||
<factorypath>
|
|
||||||
</factorypath>
|
|
|
@ -1,23 +0,0 @@
|
||||||
<?xml version="1.0" encoding="UTF-8"?>
|
|
||||||
<projectDescription>
|
|
||||||
<name>ButtonCore</name>
|
|
||||||
<comment></comment>
|
|
||||||
<projects>
|
|
||||||
</projects>
|
|
||||||
<buildSpec>
|
|
||||||
<buildCommand>
|
|
||||||
<name>org.eclipse.jdt.core.javabuilder</name>
|
|
||||||
<arguments>
|
|
||||||
</arguments>
|
|
||||||
</buildCommand>
|
|
||||||
<buildCommand>
|
|
||||||
<name>org.eclipse.m2e.core.maven2Builder</name>
|
|
||||||
<arguments>
|
|
||||||
</arguments>
|
|
||||||
</buildCommand>
|
|
||||||
</buildSpec>
|
|
||||||
<natures>
|
|
||||||
<nature>org.eclipse.m2e.core.maven2Nature</nature>
|
|
||||||
<nature>org.eclipse.jdt.core.javanature</nature>
|
|
||||||
</natures>
|
|
||||||
</projectDescription>
|
|
|
@ -1,6 +0,0 @@
|
||||||
eclipse.preferences.version=1
|
|
||||||
encoding//src/main/java=UTF-8
|
|
||||||
encoding//src/main/resources=UTF-8
|
|
||||||
encoding//src/test/java=UTF-8
|
|
||||||
encoding/<project>=UTF-8
|
|
||||||
encoding/src=UTF-8
|
|
|
@ -1,4 +0,0 @@
|
||||||
eclipse.preferences.version=1
|
|
||||||
org.eclipse.jdt.apt.aptEnabled=true
|
|
||||||
org.eclipse.jdt.apt.genSrcDir=.apt_generated
|
|
||||||
org.eclipse.jdt.apt.reconcileEnabled=true
|
|
|
@ -1,14 +0,0 @@
|
||||||
eclipse.preferences.version=1
|
|
||||||
org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled
|
|
||||||
org.eclipse.jdt.core.compiler.codegen.methodParameters=do not generate
|
|
||||||
org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.8
|
|
||||||
org.eclipse.jdt.core.compiler.codegen.unusedLocal=preserve
|
|
||||||
org.eclipse.jdt.core.compiler.compliance=1.8
|
|
||||||
org.eclipse.jdt.core.compiler.debug.lineNumber=generate
|
|
||||||
org.eclipse.jdt.core.compiler.debug.localVariable=generate
|
|
||||||
org.eclipse.jdt.core.compiler.debug.sourceFile=generate
|
|
||||||
org.eclipse.jdt.core.compiler.problem.assertIdentifier=error
|
|
||||||
org.eclipse.jdt.core.compiler.problem.enumIdentifier=error
|
|
||||||
org.eclipse.jdt.core.compiler.problem.forbiddenReference=warning
|
|
||||||
org.eclipse.jdt.core.compiler.processAnnotations=enabled
|
|
||||||
org.eclipse.jdt.core.compiler.source=1.8
|
|
|
@ -1,4 +0,0 @@
|
||||||
activeProfiles=
|
|
||||||
eclipse.preferences.version=1
|
|
||||||
resolveWorkspaceProjects=true
|
|
||||||
version=1
|
|
|
@ -1,2 +0,0 @@
|
||||||
# ButtonCore
|
|
||||||
A plugin that serves as a container for things common to many of our plugins
|
|
|
@ -1,107 +0,0 @@
|
||||||
package buttondevteam.core;
|
|
||||||
|
|
||||||
import buttondevteam.lib.TBMCCoreAPI;
|
|
||||||
import buttondevteam.lib.chat.TBMCChatAPI;
|
|
||||||
import buttondevteam.lib.chat.TBMCCommandBase;
|
|
||||||
import org.bukkit.command.Command;
|
|
||||||
import org.bukkit.command.CommandExecutor;
|
|
||||||
import org.bukkit.command.CommandSender;
|
|
||||||
import org.bukkit.command.PluginCommand;
|
|
||||||
import org.bukkit.plugin.java.JavaPlugin;
|
|
||||||
|
|
||||||
import java.util.Arrays;
|
|
||||||
|
|
||||||
public class CommandCaller implements CommandExecutor {
|
|
||||||
|
|
||||||
private CommandCaller() {
|
|
||||||
}
|
|
||||||
|
|
||||||
private static CommandCaller instance;
|
|
||||||
|
|
||||||
public static void RegisterCommand(TBMCCommandBase cmd) throws Exception {
|
|
||||||
if (instance == null)
|
|
||||||
instance = new CommandCaller();
|
|
||||||
String[] topcmd = new String[1]; //Holds out param
|
|
||||||
PluginCommand pc = getPluginCommand(cmd, topcmd);
|
|
||||||
pc.setExecutor(instance);
|
|
||||||
String[] helptext = cmd.GetHelpText(topcmd[0]);
|
|
||||||
if (helptext == null || helptext.length == 0)
|
|
||||||
throw new Exception("Command " + cmd.GetCommandPath() + " has no help text!");
|
|
||||||
pc.setUsage(helptext.length > 1 ? helptext[1] : helptext[0]);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean onCommand(CommandSender sender, Command command, String alias, String[] args) {
|
|
||||||
StringBuilder path = new StringBuilder(command.getName().toLowerCase());
|
|
||||||
for (String arg : args)
|
|
||||||
path.append(" ").append(arg);
|
|
||||||
TBMCCommandBase cmd = TBMCChatAPI.GetCommands().get(path.toString());
|
|
||||||
int argc = 0;
|
|
||||||
String[] subcmds = null;
|
|
||||||
while (cmd == null && (subcmds = TBMCChatAPI.GetSubCommands(path.toString(), sender)).length == 0 && path.toString().contains(" ")) {
|
|
||||||
path = new StringBuilder(path.substring(0, path.toString().lastIndexOf(' ')));
|
|
||||||
argc++;
|
|
||||||
cmd = TBMCChatAPI.GetCommands().get(path.toString());
|
|
||||||
}
|
|
||||||
if (cmd == null) {
|
|
||||||
if (subcmds.length > 0) //Subcmds will always have value here (see assignment above)
|
|
||||||
sender.sendMessage(subcmds);
|
|
||||||
else {
|
|
||||||
final String errormsg = "§cYou don't have access to any of this command's subcommands or it doesn't have any.";
|
|
||||||
sender.sendMessage(errormsg);
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
if (cmd.isModOnly() && (MainPlugin.permission != null ? !MainPlugin.permission.has(sender, "tbmc.admin") : !sender.isOp())) {
|
|
||||||
sender.sendMessage("§cYou need to be a mod to use this command.");
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
final String[] cmdargs = args.length > 0 ? Arrays.copyOfRange(args, args.length - argc, args.length) : args;
|
|
||||||
try {
|
|
||||||
if (!cmd.OnCommand(sender, alias, cmdargs)) {
|
|
||||||
if (cmd.GetHelpText(alias) == null) {
|
|
||||||
sender.sendMessage("Wrong usage, but there's no help text! Error is being reported to devs.");
|
|
||||||
throw new NullPointerException("GetHelpText is null for comand /" + cmd.GetCommandPath());
|
|
||||||
} else
|
|
||||||
sender.sendMessage(cmd.GetHelpText(alias));
|
|
||||||
}
|
|
||||||
} catch (Exception e) {
|
|
||||||
TBMCCoreAPI.SendException("Failed to execute command /" + cmd.GetCommandPath() + " with arguments "
|
|
||||||
+ Arrays.toString(cmdargs), e);
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void UnregisterCommand(TBMCCommandBase cmd) throws Exception {
|
|
||||||
PluginCommand pc = getPluginCommand(cmd, null);
|
|
||||||
pc.setExecutor(null); //Sets the executor to this plugin
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Gets the plugin command from the TBMC command.
|
|
||||||
*
|
|
||||||
* @param cmd The TBMC command
|
|
||||||
* @param out_topcmd An array with at least 1 elements or null
|
|
||||||
* @return The Bukkit plugin command - an exception is generated if null
|
|
||||||
* @throws Exception If the command isn't set up properly (or a different error)
|
|
||||||
*/
|
|
||||||
public static PluginCommand getPluginCommand(TBMCCommandBase cmd, String[] out_topcmd) throws Exception {
|
|
||||||
String topcmd = cmd.GetCommandPath();
|
|
||||||
if (topcmd == null)
|
|
||||||
throw new Exception("Command " + cmd.getClass().getSimpleName() + " has no command path!");
|
|
||||||
if (cmd.getPlugin() == null)
|
|
||||||
throw new Exception("Command " + cmd.GetCommandPath() + " has no plugin!");
|
|
||||||
int i;
|
|
||||||
if ((i = topcmd.indexOf(' ')) != -1) // Get top-level command
|
|
||||||
topcmd = topcmd.substring(0, i);
|
|
||||||
if (out_topcmd != null && out_topcmd.length > 0)
|
|
||||||
out_topcmd[0] = topcmd;
|
|
||||||
{
|
|
||||||
PluginCommand pc = ((JavaPlugin) cmd.getPlugin()).getCommand(topcmd);
|
|
||||||
if (pc == null)
|
|
||||||
throw new Exception("Top level command " + topcmd + " not registered in plugin.yml for plugin: "
|
|
||||||
+ cmd.getPlugin().getName());
|
|
||||||
return pc;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,17 +0,0 @@
|
||||||
package buttondevteam.core;
|
|
||||||
|
|
||||||
import buttondevteam.lib.chat.Command2;
|
|
||||||
import buttondevteam.lib.chat.CommandClass;
|
|
||||||
import buttondevteam.lib.chat.ICommand2MC;
|
|
||||||
import org.bukkit.command.CommandSender;
|
|
||||||
|
|
||||||
@CommandClass
|
|
||||||
public class ThorpeCommand extends ICommand2MC {
|
|
||||||
@Command2.Subcommand //TODO: Main permissions (groups) like 'mod'
|
|
||||||
public void reload(CommandSender sender) {
|
|
||||||
if (MainPlugin.Instance.tryReloadConfig())
|
|
||||||
sender.sendMessage("§bConfig reloaded.");
|
|
||||||
else
|
|
||||||
sender.sendMessage("§cFailed to reload config. Check console.");
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,231 +0,0 @@
|
||||||
package buttondevteam.core.component.channel;
|
|
||||||
|
|
||||||
import buttondevteam.core.ComponentManager;
|
|
||||||
import buttondevteam.core.MainPlugin;
|
|
||||||
import buttondevteam.lib.architecture.Component;
|
|
||||||
import buttondevteam.lib.architecture.ConfigData;
|
|
||||||
import buttondevteam.lib.chat.Color;
|
|
||||||
import com.google.common.collect.Lists;
|
|
||||||
import org.bukkit.Bukkit;
|
|
||||||
import org.bukkit.command.CommandSender;
|
|
||||||
import org.bukkit.entity.Player;
|
|
||||||
|
|
||||||
import javax.annotation.Nullable;
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.Collections;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.function.BiFunction;
|
|
||||||
import java.util.function.BiPredicate;
|
|
||||||
import java.util.function.Function;
|
|
||||||
import java.util.function.Predicate;
|
|
||||||
import java.util.stream.Stream;
|
|
||||||
|
|
||||||
public class Channel {
|
|
||||||
/**
|
|
||||||
* Specifies a score that means it's OK to send - but it does not define any groups, only send or not send. See {@link #GROUP_EVERYONE}
|
|
||||||
*/
|
|
||||||
public static final int SCORE_SEND_OK = 0;
|
|
||||||
/**
|
|
||||||
* Specifies a score that means the user doesn't have permission to see or send the message. Any negative value has the same effect.
|
|
||||||
*/
|
|
||||||
public static final int SCORE_SEND_NOPE = -1;
|
|
||||||
/**
|
|
||||||
* Send the message to everyone <i>who has access to the channel</i> - this does not necessarily mean all players
|
|
||||||
*/
|
|
||||||
public static final String GROUP_EVERYONE = "everyone";
|
|
||||||
|
|
||||||
private static ChannelComponent component;
|
|
||||||
|
|
||||||
private String defDisplayName;
|
|
||||||
private Color defColor;
|
|
||||||
|
|
||||||
private void throwGame() {
|
|
||||||
if (component == null) throw new RuntimeException("Cannot access channel properties until registered!");
|
|
||||||
}
|
|
||||||
|
|
||||||
public final ConfigData<Boolean> Enabled() {
|
|
||||||
throwGame();
|
|
||||||
return component.getConfig().getData(ID + ".enabled", true);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Must start with a color code
|
|
||||||
*/
|
|
||||||
public final ConfigData<String> DisplayName() {
|
|
||||||
throwGame();
|
|
||||||
return component.getConfig().getData(ID + ".displayName", defDisplayName); //TODO: Use config map
|
|
||||||
}
|
|
||||||
|
|
||||||
public final ConfigData<Color> Color() {
|
|
||||||
throwGame();
|
|
||||||
return component.getConfig().getData(ID + ".color", defColor, c -> Color.valueOf((String) c), Enum::toString);
|
|
||||||
}
|
|
||||||
public final String ID;
|
|
||||||
|
|
||||||
@SuppressWarnings("unchecked")
|
|
||||||
public ConfigData<String[]> IDs() {
|
|
||||||
throwGame();
|
|
||||||
return component.getConfig().getData(ID + ".IDs", new String[0], l -> ((List<String>) l).toArray(new String[0]), Lists::newArrayList);
|
|
||||||
}
|
|
||||||
/**
|
|
||||||
* Filters both the sender and the targets
|
|
||||||
*/
|
|
||||||
private final Function<CommandSender, RecipientTestResult> filteranderrormsg;
|
|
||||||
|
|
||||||
private static final List<Channel> channels = new ArrayList<>();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Creates a channel.
|
|
||||||
*
|
|
||||||
* @param displayname The name that should appear at the start of the message. <b>A chat color is expected at the beginning (§9).</b>
|
|
||||||
* @param color The default color of the messages sent in the channel
|
|
||||||
* @param command The command to be used for the channel <i>without /</i>. For example "mod". It's also used for scoreboard objective names.
|
|
||||||
* @param filteranderrormsg Checks all senders against the criteria provided here and sends the message if the index matches the sender's - if no score at all, displays the error.<br>
|
|
||||||
* May be null to send to everyone.
|
|
||||||
*/
|
|
||||||
public Channel(String displayname, Color color, String command,
|
|
||||||
Function<CommandSender, RecipientTestResult> filteranderrormsg) {
|
|
||||||
defDisplayName = displayname;
|
|
||||||
defColor = color;
|
|
||||||
ID = command;
|
|
||||||
this.filteranderrormsg = filteranderrormsg;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Must be only called from a subclass - otherwise it'll throw an exception.
|
|
||||||
*
|
|
||||||
* @see Channel#Channel(String, Color, String, Function)
|
|
||||||
*/
|
|
||||||
@SuppressWarnings("unchecked")
|
|
||||||
protected <T extends Channel> Channel(String displayname, Color color, String command,
|
|
||||||
BiFunction<T, CommandSender, RecipientTestResult> filteranderrormsg) {
|
|
||||||
defDisplayName = displayname;
|
|
||||||
defColor = color;
|
|
||||||
ID = command;
|
|
||||||
this.filteranderrormsg = s -> filteranderrormsg.apply((T) this, s);
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean isGlobal() {
|
|
||||||
return filteranderrormsg == null;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Note: Errors are sent to the sender automatically
|
|
||||||
*
|
|
||||||
* @param sender The user we're sending to
|
|
||||||
* @param score The (source) score to compare with the user's
|
|
||||||
*/
|
|
||||||
public boolean shouldSendTo(CommandSender sender, int score) {
|
|
||||||
return score == getMCScore(sender); //If there's any error, the score won't be equal
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Note: Errors are sent to the sender automatically
|
|
||||||
*/
|
|
||||||
public int getMCScore(CommandSender sender) {
|
|
||||||
return getRTR(sender).score; //No need to check if there was an error
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Note: Errors are sent to the sender automatically<br>
|
|
||||||
* <p>
|
|
||||||
* Null means don't send
|
|
||||||
*/
|
|
||||||
@Nullable
|
|
||||||
public String getGroupID(CommandSender sender) {
|
|
||||||
return getRTR(sender).groupID; //No need to check if there was an error
|
|
||||||
}
|
|
||||||
|
|
||||||
public RecipientTestResult getRTR(CommandSender sender) {
|
|
||||||
if (filteranderrormsg == null)
|
|
||||||
return new RecipientTestResult(SCORE_SEND_OK, GROUP_EVERYONE);
|
|
||||||
return filteranderrormsg.apply(sender);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get a stream of the enabled channels
|
|
||||||
*
|
|
||||||
* @return Only the enabled channels
|
|
||||||
*/
|
|
||||||
public static Stream<Channel> getChannels() {
|
|
||||||
return channels.stream().filter(ch -> ch.Enabled().get());
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Return all channels whether they're enabled or not
|
|
||||||
*
|
|
||||||
* @return A list of all channels
|
|
||||||
*/
|
|
||||||
public static List<Channel> getChannelList() {
|
|
||||||
return Collections.unmodifiableList(channels);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Convenience method for the function parameter of {@link #Channel(String, Color, String, Function)}. It checks if the sender is OP or optionally has the specified group. The error message is
|
|
||||||
* generated automatically.
|
|
||||||
*
|
|
||||||
* @param permgroup The group that can access the channel or <b>null</b> to only allow OPs.
|
|
||||||
* @return If has access
|
|
||||||
*/
|
|
||||||
public static Function<CommandSender, RecipientTestResult> inGroupFilter(String permgroup) {
|
|
||||||
return noScoreResult(
|
|
||||||
s -> s.isOp() || (permgroup != null && (s instanceof Player && MainPlugin.permission != null && MainPlugin.permission.playerInGroup((Player) s, permgroup))),
|
|
||||||
"You need to be a(n) " + (permgroup != null ? permgroup : "OP") + " to use this channel.");
|
|
||||||
}
|
|
||||||
|
|
||||||
public static Function<CommandSender, RecipientTestResult> noScoreResult(Predicate<CommandSender> filter,
|
|
||||||
String errormsg) {
|
|
||||||
return s -> filter.test(s) ? new RecipientTestResult(SCORE_SEND_OK, GROUP_EVERYONE) : new RecipientTestResult(errormsg);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static <T extends Channel> BiFunction<T, CommandSender, RecipientTestResult> noScoreResult(
|
|
||||||
BiPredicate<T, CommandSender> filter, String errormsg) {
|
|
||||||
return (this_, s) -> filter.test(this_, s) ? new RecipientTestResult(SCORE_SEND_OK, GROUP_EVERYONE) : new RecipientTestResult(errormsg);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static Channel GlobalChat;
|
|
||||||
public static Channel AdminChat;
|
|
||||||
public static Channel ModChat;
|
|
||||||
|
|
||||||
public static void RegisterChannel(Channel channel) {
|
|
||||||
if (!channel.isGlobal() && !ComponentManager.isEnabled(ChannelComponent.class))
|
|
||||||
return; //Allow registering the global chat (and I guess other chats like the RP chat)
|
|
||||||
if (component == null)
|
|
||||||
component = (ChannelComponent) Component.getComponents().get(ChannelComponent.class);
|
|
||||||
if (component == null)
|
|
||||||
throw new RuntimeException("Attempting to register a channel before the component is registered!");
|
|
||||||
channels.add(channel);
|
|
||||||
Bukkit.getScheduler().runTask(MainPlugin.Instance, () -> Bukkit.getPluginManager().callEvent(new ChatChannelRegisterEvent(channel))); // Wait for server start
|
|
||||||
}
|
|
||||||
|
|
||||||
public static class RecipientTestResult {
|
|
||||||
public final String errormessage;
|
|
||||||
public final int score; // Anything below 0 is "never send"
|
|
||||||
public final String groupID;
|
|
||||||
public static final RecipientTestResult ALL = new RecipientTestResult(SCORE_SEND_OK, GROUP_EVERYONE);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Creates a result that indicates an <b>error</b>
|
|
||||||
*
|
|
||||||
* @param errormessage The error message to show the sender if they don't meet the criteria.
|
|
||||||
*/
|
|
||||||
public RecipientTestResult(String errormessage) {
|
|
||||||
this.errormessage = errormessage;
|
|
||||||
this.score = SCORE_SEND_NOPE;
|
|
||||||
this.groupID = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Creates a result that indicates a <b>success</b>
|
|
||||||
*
|
|
||||||
* @param score The score that identifies the target group. <b>Must be non-negative.</b> For example, the index of the town or nation to send to.
|
|
||||||
* @param groupID The ID of the target group.
|
|
||||||
*/
|
|
||||||
public RecipientTestResult(int score, String groupID) {
|
|
||||||
if (score < 0) throw new IllegalArgumentException("Score must be non-negative!");
|
|
||||||
this.score = score;
|
|
||||||
this.groupID = groupID;
|
|
||||||
this.errormessage = null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,34 +0,0 @@
|
||||||
package buttondevteam.core.component.channel;
|
|
||||||
|
|
||||||
import buttondevteam.lib.TBMCSystemChatEvent;
|
|
||||||
import buttondevteam.lib.architecture.Component;
|
|
||||||
import org.bukkit.plugin.java.JavaPlugin;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Manages chat channels. If disabled, only global channels will be registered.
|
|
||||||
*/
|
|
||||||
public class ChannelComponent extends Component {
|
|
||||||
static TBMCSystemChatEvent.BroadcastTarget roomJoinLeave;
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void register(JavaPlugin plugin) {
|
|
||||||
super.register(plugin);
|
|
||||||
roomJoinLeave = TBMCSystemChatEvent.BroadcastTarget.add("roomJoinLeave"); //Even if it's disabled, global channels continue to work
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void unregister(JavaPlugin plugin) {
|
|
||||||
super.unregister(plugin);
|
|
||||||
TBMCSystemChatEvent.BroadcastTarget.remove(roomJoinLeave);
|
|
||||||
roomJoinLeave = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void enable() {
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void disable() {
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,65 +0,0 @@
|
||||||
package buttondevteam.core.component.members;
|
|
||||||
|
|
||||||
import buttondevteam.core.MainPlugin;
|
|
||||||
import buttondevteam.lib.architecture.Component;
|
|
||||||
import buttondevteam.lib.architecture.ConfigData;
|
|
||||||
import org.bukkit.Statistic;
|
|
||||||
import org.bukkit.event.EventHandler;
|
|
||||||
import org.bukkit.event.Listener;
|
|
||||||
import org.bukkit.event.player.PlayerJoinEvent;
|
|
||||||
|
|
||||||
import java.time.Instant;
|
|
||||||
import java.time.temporal.ChronoUnit;
|
|
||||||
import java.util.Date;
|
|
||||||
|
|
||||||
import static buttondevteam.core.MainPlugin.permission;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Allows giving a 'member' group over some time elapsed OR played.
|
|
||||||
*/
|
|
||||||
public class MemberComponent extends Component<MainPlugin> implements Listener {
|
|
||||||
/**
|
|
||||||
* The permission group to give to the player
|
|
||||||
*/
|
|
||||||
ConfigData<String> memberGroup() {
|
|
||||||
return getConfig().getData("memberGroup", "member");
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The amount of hours needed to play before promotion
|
|
||||||
*/
|
|
||||||
private ConfigData<Integer> playedHours() {
|
|
||||||
return getConfig().getData("playedHours", 12);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The amount of days passed since first login
|
|
||||||
*/
|
|
||||||
private ConfigData<Integer> registeredForDays() {
|
|
||||||
return getConfig().getData("registeredForDays", 7);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void enable() {
|
|
||||||
registerListener(this);
|
|
||||||
registerCommand(new MemberCommand(this));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void disable() {
|
|
||||||
}
|
|
||||||
|
|
||||||
@EventHandler
|
|
||||||
public void onPlayerJoin(PlayerJoinEvent event) {
|
|
||||||
if (permission != null && !permission.playerInGroup(event.getPlayer(), memberGroup().get())
|
|
||||||
&& (new Date(event.getPlayer().getFirstPlayed()).toInstant().plus(registeredForDays().get(), ChronoUnit.DAYS).isBefore(Instant.now())
|
|
||||||
|| event.getPlayer().getStatistic(Statistic.PLAY_ONE_TICK) > 20 * 3600 * playedHours().get())) {
|
|
||||||
if (permission.playerAddGroup(null, event.getPlayer(), memberGroup().get())) {
|
|
||||||
event.getPlayer().sendMessage("§bYou are a member now. YEEHAW");
|
|
||||||
MainPlugin.Instance.getLogger().info("Added " + event.getPlayer().getName() + " as a member.");
|
|
||||||
} else {
|
|
||||||
MainPlugin.Instance.getLogger().warning("Failed to assign the member role! Please make sure the member group exists or disable the component if it's unused.");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,48 +0,0 @@
|
||||||
package buttondevteam.core.component.restart;
|
|
||||||
|
|
||||||
import buttondevteam.core.component.channel.Channel;
|
|
||||||
import buttondevteam.lib.chat.CommandClass;
|
|
||||||
import buttondevteam.lib.chat.TBMCChatAPI;
|
|
||||||
import buttondevteam.lib.chat.TBMCCommandBase;
|
|
||||||
import lombok.Getter;
|
|
||||||
import lombok.RequiredArgsConstructor;
|
|
||||||
import org.bukkit.Bukkit;
|
|
||||||
import org.bukkit.ChatColor;
|
|
||||||
import org.bukkit.command.CommandSender;
|
|
||||||
|
|
||||||
@CommandClass(path = "primerestart", modOnly = true)
|
|
||||||
@RequiredArgsConstructor
|
|
||||||
public class PrimeRestartCommand extends TBMCCommandBase {
|
|
||||||
private final RestartComponent component;
|
|
||||||
@Override
|
|
||||||
public boolean OnCommand(CommandSender sender, String alias, String[] args) {
|
|
||||||
loud = args.length > 0;
|
|
||||||
if (Bukkit.getOnlinePlayers().size() > 0) {
|
|
||||||
sender.sendMessage("§bPlayers online, restart delayed.");
|
|
||||||
if (loud)
|
|
||||||
TBMCChatAPI.SendSystemMessage(Channel.GlobalChat, Channel.RecipientTestResult.ALL, ChatColor.DARK_RED + "The server will restart as soon as nobody is online.", component.getRestartBroadcast());
|
|
||||||
plsrestart = true;
|
|
||||||
} else {
|
|
||||||
sender.sendMessage("§bNobody is online. Restarting now.");
|
|
||||||
if (loud)
|
|
||||||
TBMCChatAPI.SendSystemMessage(Channel.GlobalChat, Channel.RecipientTestResult.ALL, "§cNobody is online. Restarting server.", component.getRestartBroadcast());
|
|
||||||
Bukkit.spigot().restart();
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Getter
|
|
||||||
private static boolean plsrestart = false;
|
|
||||||
@Getter
|
|
||||||
private static boolean loud = false;
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String[] GetHelpText(String alias) {
|
|
||||||
return new String[]{ //
|
|
||||||
"§6---- Prime restart ----", //
|
|
||||||
"Restarts the server as soon as nobody is online.", //
|
|
||||||
"To be loud, type something after, like /primerestart lol (it doesn't matter what you write)", //
|
|
||||||
"To be silent, don't type anything" //
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,51 +0,0 @@
|
||||||
package buttondevteam.core.component.towny;
|
|
||||||
|
|
||||||
import buttondevteam.core.ComponentManager;
|
|
||||||
import buttondevteam.core.MainPlugin;
|
|
||||||
import buttondevteam.lib.TBMCCoreAPI;
|
|
||||||
import buttondevteam.lib.architecture.Component;
|
|
||||||
import com.palmergames.bukkit.towny.Towny;
|
|
||||||
import com.palmergames.bukkit.towny.exceptions.AlreadyRegisteredException;
|
|
||||||
import com.palmergames.bukkit.towny.exceptions.NotRegisteredException;
|
|
||||||
import com.palmergames.bukkit.towny.object.Resident;
|
|
||||||
import com.palmergames.bukkit.towny.object.TownyUniverse;
|
|
||||||
import org.bukkit.Bukkit;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Automatically renames Towny players if they changed their Minecraft name
|
|
||||||
*/
|
|
||||||
public class TownyComponent extends Component<MainPlugin> {
|
|
||||||
@Override
|
|
||||||
protected void enable() {
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void disable() {
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Only renames the resident if this component is enabled. Used to handle name changes.
|
|
||||||
*
|
|
||||||
* @param oldName The player's old name as known by us
|
|
||||||
* @param newName The player's new name
|
|
||||||
*/
|
|
||||||
public static void renameInTowny(String oldName, String newName) {
|
|
||||||
if (!ComponentManager.isEnabled(TownyComponent.class))
|
|
||||||
return; TownyUniverse tu = Towny.getPlugin(Towny.class).getTownyUniverse();
|
|
||||||
Resident resident = tu.getResidentMap().get(oldName.toLowerCase()); //The map keys are lowercase
|
|
||||||
if (resident == null) {
|
|
||||||
Bukkit.getLogger().warning("Resident not found - couldn't rename in Towny.");
|
|
||||||
TBMCCoreAPI.sendDebugMessage("Resident not found - couldn't rename in Towny.");
|
|
||||||
} else if (tu.getResidentMap().contains(newName.toLowerCase())) {
|
|
||||||
Bukkit.getLogger().warning("Target resident name is already in use."); // TODO: Handle
|
|
||||||
TBMCCoreAPI.sendDebugMessage("Target resident name is already in use.");
|
|
||||||
} else
|
|
||||||
try {
|
|
||||||
TownyUniverse.getDataSource().renamePlayer(resident, newName); //Fixed in Towny 0.91.1.2
|
|
||||||
} catch (AlreadyRegisteredException e) {
|
|
||||||
TBMCCoreAPI.SendException("Failed to rename resident, there's already one with this name.", e);
|
|
||||||
} catch (NotRegisteredException e) {
|
|
||||||
TBMCCoreAPI.SendException("Failed to rename resident, the resident isn't registered.", e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,195 +0,0 @@
|
||||||
package buttondevteam.core.component.updater;
|
|
||||||
|
|
||||||
import buttondevteam.lib.TBMCCoreAPI;
|
|
||||||
import com.google.gson.JsonArray;
|
|
||||||
import com.google.gson.JsonElement;
|
|
||||||
import com.google.gson.JsonObject;
|
|
||||||
import com.google.gson.JsonParser;
|
|
||||||
import org.apache.commons.io.FileUtils;
|
|
||||||
import org.bukkit.Bukkit;
|
|
||||||
import org.bukkit.command.CommandSender;
|
|
||||||
import org.bukkit.event.Event;
|
|
||||||
import org.bukkit.event.HandlerList;
|
|
||||||
|
|
||||||
import java.io.File;
|
|
||||||
import java.io.FileNotFoundException;
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.net.URL;
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.Optional;
|
|
||||||
|
|
||||||
public class PluginUpdater {
|
|
||||||
private PluginUpdater() {
|
|
||||||
}
|
|
||||||
|
|
||||||
public static final File updatedir = new File("TBMC", "pluginupdates");
|
|
||||||
/**
|
|
||||||
* See {@link TBMCCoreAPI#UpdatePlugin(String, CommandSender, String)}
|
|
||||||
*/
|
|
||||||
public static boolean UpdatePlugin(String name, CommandSender sender, String branch) {
|
|
||||||
if (!updatedir.exists() && !updatedir.mkdirs()) {
|
|
||||||
error(sender, "Failed to create update directory!");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
info(sender, "Checking plugin name...");
|
|
||||||
List<String> plugins = GetPluginNames();
|
|
||||||
String correctname = null;
|
|
||||||
for (String plugin : plugins) {
|
|
||||||
if (plugin.equalsIgnoreCase(name)) {
|
|
||||||
correctname = plugin; // Fixes capitalization
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (correctname == null) {
|
|
||||||
error(sender, "Can't find plugin: " + name);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
info(sender, "Checking branch name...");
|
|
||||||
if (!TBMCCoreAPI.IsTestServer() && !branch.equalsIgnoreCase("master")) {
|
|
||||||
error(sender, "The server is in production mode, updating only allowed from master!");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
Optional<String> correctbranch = GetPluginBranches(correctname).stream().filter(b -> b.equalsIgnoreCase(branch))
|
|
||||||
.findAny();
|
|
||||||
if (!correctbranch.isPresent()) {
|
|
||||||
error(sender, "Can't find branch \"" + branch + "\" for plugin \"" + correctname + "\"");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
if (isNotMaven(correctname, correctbranch.get())) {
|
|
||||||
error(sender, "The plugin doesn't appear to have a pom.xml. Make sure it's a Maven project.");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
info(sender, "Updating TBMC plugin: " + correctname + " from " + correctbranch.get());
|
|
||||||
return updatePluginJitPack(sender, correctname, correctbranch.get());
|
|
||||||
}
|
|
||||||
|
|
||||||
private static boolean updatePluginJitPack(CommandSender sender, String correctname,
|
|
||||||
String correctbranch) {
|
|
||||||
URL url;
|
|
||||||
File result = new File(updatedir, correctname + ".jar");
|
|
||||||
try {
|
|
||||||
url = new URL("https://jitpack.io/com/github/TBMCPlugins/"
|
|
||||||
+ (correctname.equals("ButtonCore") ? "ButtonCore/ButtonCore" : correctname) + "/"
|
|
||||||
+ correctbranch + "-SNAPSHOT/" + correctname + "-" + correctbranch + "-SNAPSHOT.jar"); // ButtonCore exception required since it hosts Towny as well
|
|
||||||
FileUtils.copyURLToFile(url, result);
|
|
||||||
if (!result.exists() || result.length() < 25) {
|
|
||||||
result.delete();
|
|
||||||
error(sender, "The downloaded JAR for " + correctname + " from " + correctbranch
|
|
||||||
+ " is too small (smnaller than 25 bytes). Am I downloading from the right place?");
|
|
||||||
return false;
|
|
||||||
} else {
|
|
||||||
info(sender, "Updating plugin " + correctname + " from " + correctbranch + " done!");
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
} catch (FileNotFoundException e) {
|
|
||||||
error(sender,
|
|
||||||
"Can't find JAR for " + correctname + " from " + correctbranch
|
|
||||||
+ ", the build probably failed. Build log (scroll to bottom):" + "\n"
|
|
||||||
+ "https://jitpack.io/com/github/TBMCPlugins/" + correctname + "/" + correctbranch
|
|
||||||
+ "-SNAPSHOT/build.log\nIf you'd like to rebuild the same commit, go to:\nhttps://jitpack.io/#TBMCPlugins/"
|
|
||||||
+ correctname + "\nAnd delete the newest build.");
|
|
||||||
} catch (IOException e) {
|
|
||||||
error(sender, "IO error while updating " + correctname + "\n" + e.getMessage());
|
|
||||||
} catch (Exception e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
error(sender, "Unknown error while updating " + correctname + ": " + e);
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Checks if pom.xml is not present for the project.
|
|
||||||
*
|
|
||||||
* @param pluginname
|
|
||||||
* Does not have to match case
|
|
||||||
* @param branch
|
|
||||||
* Does not have to match case
|
|
||||||
*/
|
|
||||||
public static boolean isNotMaven(String pluginname, String branch) {
|
|
||||||
try {
|
|
||||||
return TBMCCoreAPI
|
|
||||||
.DownloadString(
|
|
||||||
"https://raw.githubusercontent.com/TBMCPlugins/" + pluginname + "/" + branch + "/pom.xml")
|
|
||||||
.equals("404: Not Found\n");
|
|
||||||
} catch (IOException e1) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private static void error(CommandSender sender, String message) {
|
|
||||||
if (!sender.equals(Bukkit.getConsoleSender()))
|
|
||||||
Bukkit.getLogger().warning(message);
|
|
||||||
sender.sendMessage("§c" + message);
|
|
||||||
}
|
|
||||||
|
|
||||||
private static void info(CommandSender sender, String message) {
|
|
||||||
if (!sender.equals(Bukkit.getConsoleSender()))
|
|
||||||
Bukkit.getLogger().info(message);
|
|
||||||
sender.sendMessage("§b" + message);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Retrieves all the repository names from the GitHub organization.
|
|
||||||
*
|
|
||||||
* @return A list of names
|
|
||||||
*/
|
|
||||||
public static List<String> GetPluginNames() {
|
|
||||||
List<String> ret = new ArrayList<>();
|
|
||||||
try {
|
|
||||||
String resp = TBMCCoreAPI.DownloadString("https://api.github.com/orgs/" + "TBMCPlugins" + "/repos"); //TODO: PluginUpdater
|
|
||||||
JsonArray arr = new JsonParser().parse(resp).getAsJsonArray();
|
|
||||||
for (JsonElement obj : arr) {
|
|
||||||
JsonObject jobj = obj.getAsJsonObject();
|
|
||||||
ret.add(jobj.get("name").getAsString());
|
|
||||||
}
|
|
||||||
} catch (Exception e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
}
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Retrieves all the branches from the plugin repository.
|
|
||||||
*
|
|
||||||
* @return A list of names
|
|
||||||
*/
|
|
||||||
public static List<String> GetPluginBranches(String plugin) {
|
|
||||||
List<String> ret = new ArrayList<>();
|
|
||||||
try {
|
|
||||||
String resp = TBMCCoreAPI
|
|
||||||
.DownloadString("https://api.github.com/repos/TBMCPlugins/" + plugin + "/branches");
|
|
||||||
JsonArray arr = new JsonParser().parse(resp).getAsJsonArray();
|
|
||||||
for (JsonElement obj : arr) {
|
|
||||||
JsonObject jobj = obj.getAsJsonObject();
|
|
||||||
ret.add(jobj.get("name").getAsString());
|
|
||||||
}
|
|
||||||
} catch (Exception e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
}
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static class UpdatedEvent extends Event {
|
|
||||||
private static final HandlerList handlers = new HandlerList();
|
|
||||||
|
|
||||||
private final JsonObject data;
|
|
||||||
|
|
||||||
public UpdatedEvent(JsonObject data) {
|
|
||||||
this.data = data;
|
|
||||||
}
|
|
||||||
|
|
||||||
public JsonObject getData() {
|
|
||||||
return data;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public HandlerList getHandlers() {
|
|
||||||
return handlers;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static HandlerList getHandlerList() {
|
|
||||||
return handlers;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,20 +0,0 @@
|
||||||
package buttondevteam.core.component.updater;
|
|
||||||
|
|
||||||
import buttondevteam.core.MainPlugin;
|
|
||||||
import buttondevteam.lib.architecture.Component;
|
|
||||||
import buttondevteam.lib.chat.TBMCChatAPI;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Downloads plugin updates built from their source using JitPack - older code
|
|
||||||
*/
|
|
||||||
public class PluginUpdaterComponent extends Component<MainPlugin> { //TODO: Config
|
|
||||||
@Override
|
|
||||||
public void enable() {
|
|
||||||
TBMCChatAPI.AddCommand(this, new UpdatePluginCommand());
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void disable() { //Commands are automatically unregistered
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,41 +0,0 @@
|
||||||
package buttondevteam.core.component.updater;
|
|
||||||
|
|
||||||
import buttondevteam.core.MainPlugin;
|
|
||||||
import buttondevteam.lib.TBMCCoreAPI;
|
|
||||||
import buttondevteam.lib.chat.CommandClass;
|
|
||||||
import buttondevteam.lib.chat.TBMCCommandBase;
|
|
||||||
import org.bukkit.Bukkit;
|
|
||||||
import org.bukkit.command.CommandSender;
|
|
||||||
|
|
||||||
@CommandClass(modOnly = true)
|
|
||||||
public class UpdatePluginCommand extends TBMCCommandBase {
|
|
||||||
@Override
|
|
||||||
public boolean OnCommand(CommandSender sender, String alias, String[] args) {
|
|
||||||
Bukkit.getScheduler().runTaskAsynchronously(MainPlugin.Instance, () -> {
|
|
||||||
if (args.length == 0) {
|
|
||||||
sender.sendMessage("Downloading plugin names...");
|
|
||||||
boolean first = true;
|
|
||||||
for (String plugin : PluginUpdater.GetPluginNames()) {
|
|
||||||
if (first) {
|
|
||||||
sender.sendMessage("§6---- Plugin names ----");
|
|
||||||
first = false;
|
|
||||||
}
|
|
||||||
sender.sendMessage("- " + plugin);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
TBMCCoreAPI.UpdatePlugin(args[0], sender, args.length == 1 ? "master" : args[1]);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String[] GetHelpText(String alias) {
|
|
||||||
return new String[] { //
|
|
||||||
"§6---- Update plugin ----", //
|
|
||||||
"This command downloads the latest version of a TBMC plugin from GitHub", //
|
|
||||||
"To update a plugin: /" + alias + " <plugin>", //
|
|
||||||
"To list the plugin names: /" + alias //
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,49 +0,0 @@
|
||||||
package buttondevteam.core.component.votifier;
|
|
||||||
|
|
||||||
import buttondevteam.core.MainPlugin;
|
|
||||||
import buttondevteam.lib.architecture.Component;
|
|
||||||
import buttondevteam.lib.architecture.ConfigData;
|
|
||||||
import com.vexsoftware.votifier.model.Vote;
|
|
||||||
import com.vexsoftware.votifier.model.VotifierEvent;
|
|
||||||
import lombok.RequiredArgsConstructor;
|
|
||||||
import net.milkbowl.vault.economy.Economy;
|
|
||||||
import org.bukkit.Bukkit;
|
|
||||||
import org.bukkit.entity.Player;
|
|
||||||
import org.bukkit.event.EventHandler;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Do not use (EULA)
|
|
||||||
*/
|
|
||||||
@RequiredArgsConstructor
|
|
||||||
public class VotifierComponent extends Component<MainPlugin> {
|
|
||||||
private final Economy economy;
|
|
||||||
|
|
||||||
private ConfigData<Double> rewardAmount() {
|
|
||||||
return getConfig().getData("rewardAmount", 0.0);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void enable() {
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void disable() {
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
@EventHandler
|
|
||||||
@SuppressWarnings("deprecation")
|
|
||||||
public void onVotifierEvent(VotifierEvent event) {
|
|
||||||
Vote vote = event.getVote();
|
|
||||||
getPlugin().getLogger().info("Vote: " + vote);
|
|
||||||
org.bukkit.OfflinePlayer op = Bukkit.getOfflinePlayer(vote.getUsername());
|
|
||||||
Player p = Bukkit.getPlayer(vote.getUsername());
|
|
||||||
if (op != null) {
|
|
||||||
economy.depositPlayer(op, rewardAmount().get());
|
|
||||||
}
|
|
||||||
if (p != null) {
|
|
||||||
p.sendMessage("§bThanks for voting! $50 was added to your account.");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,111 +0,0 @@
|
||||||
package buttondevteam.lib.architecture;
|
|
||||||
|
|
||||||
import buttondevteam.core.ComponentManager;
|
|
||||||
import buttondevteam.lib.TBMCCoreAPI;
|
|
||||||
import buttondevteam.lib.chat.Command2MC;
|
|
||||||
import buttondevteam.lib.chat.TBMCChatAPI;
|
|
||||||
import lombok.AccessLevel;
|
|
||||||
import lombok.Getter;
|
|
||||||
import lombok.experimental.var;
|
|
||||||
import org.bukkit.plugin.java.JavaPlugin;
|
|
||||||
|
|
||||||
import java.lang.annotation.ElementType;
|
|
||||||
import java.lang.annotation.Retention;
|
|
||||||
import java.lang.annotation.RetentionPolicy;
|
|
||||||
import java.lang.annotation.Target;
|
|
||||||
import java.util.Optional;
|
|
||||||
import java.util.Stack;
|
|
||||||
|
|
||||||
@HasConfig
|
|
||||||
public abstract class ButtonPlugin extends JavaPlugin {
|
|
||||||
@Getter
|
|
||||||
private static Command2MC command2MC = new Command2MC();
|
|
||||||
@Getter(AccessLevel.PROTECTED)
|
|
||||||
private IHaveConfig iConfig;
|
|
||||||
@Getter(AccessLevel.PROTECTED)
|
|
||||||
private IHaveConfig data; //TODO
|
|
||||||
private boolean loaded = false;
|
|
||||||
/**
|
|
||||||
* Used to unregister components in the right order - and to reload configs
|
|
||||||
*/
|
|
||||||
@Getter
|
|
||||||
private Stack<Component<?>> componentStack = new Stack<>();
|
|
||||||
|
|
||||||
protected abstract void pluginEnable();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Called after the components are unregistered
|
|
||||||
*/
|
|
||||||
protected abstract void pluginDisable();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Called before the components are unregistered
|
|
||||||
*/
|
|
||||||
protected void pluginPreDisable() {
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public final void onEnable() {
|
|
||||||
loadConfig();
|
|
||||||
try {
|
|
||||||
pluginEnable();
|
|
||||||
} catch (Exception e) {
|
|
||||||
TBMCCoreAPI.SendException("Error while enabling plugin " + getName() + "!", e);
|
|
||||||
}
|
|
||||||
if (configGenAllowed(this)) //If it's not disabled (by default it's not)
|
|
||||||
IHaveConfig.pregenConfig(this, null);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void loadConfig() {
|
|
||||||
var section = super.getConfig().getConfigurationSection("global");
|
|
||||||
if (section == null) section = super.getConfig().createSection("global");
|
|
||||||
iConfig = new IHaveConfig(section, this::saveConfig);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public final void onDisable() {
|
|
||||||
try {
|
|
||||||
pluginPreDisable();
|
|
||||||
ComponentManager.unregComponents(this);
|
|
||||||
pluginDisable();
|
|
||||||
saveConfig();
|
|
||||||
iConfig = null; //Clearing the hashmap is not enough, we need to update the section as well
|
|
||||||
TBMCChatAPI.RemoveCommands(this);
|
|
||||||
} catch (Exception e) {
|
|
||||||
TBMCCoreAPI.SendException("Error while disabling plugin " + getName() + "!", e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void reloadConfig() {
|
|
||||||
tryReloadConfig();
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean tryReloadConfig() {
|
|
||||||
if (!justReload()) return false;
|
|
||||||
loadConfig();
|
|
||||||
componentStack.forEach(c -> Component.updateConfig(this, c));
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean justReload() {
|
|
||||||
if (loaded && ConfigData.saveNow(getConfig())) {
|
|
||||||
getLogger().warning("Saved pending configuration changes to the file, didn't reload (try again).");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
super.reloadConfig();
|
|
||||||
loaded = true; //Needed because for the first time it uses reloadConfig() to load it
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Retention(RetentionPolicy.RUNTIME)
|
|
||||||
@Target(ElementType.TYPE)
|
|
||||||
public @interface ConfigOpts {
|
|
||||||
boolean disableConfigGen() default false;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static boolean configGenAllowed(Object obj) {
|
|
||||||
return !Optional.ofNullable(obj.getClass().getAnnotation(ConfigOpts.class))
|
|
||||||
.map(ConfigOpts::disableConfigGen).orElse(false);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,150 +0,0 @@
|
||||||
package buttondevteam.lib.architecture;
|
|
||||||
|
|
||||||
import buttondevteam.core.MainPlugin;
|
|
||||||
import buttondevteam.lib.ThorpeUtils;
|
|
||||||
import lombok.AccessLevel;
|
|
||||||
import lombok.AllArgsConstructor;
|
|
||||||
import lombok.Getter;
|
|
||||||
import lombok.Setter;
|
|
||||||
import org.bukkit.Bukkit;
|
|
||||||
import org.bukkit.configuration.Configuration;
|
|
||||||
import org.bukkit.configuration.ConfigurationSection;
|
|
||||||
import org.bukkit.configuration.file.YamlConfiguration;
|
|
||||||
import org.bukkit.scheduler.BukkitTask;
|
|
||||||
|
|
||||||
import java.lang.reflect.Array;
|
|
||||||
import java.util.HashMap;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.Objects;
|
|
||||||
import java.util.function.Function;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Use the getter/setter constructor if {@link T} isn't a primitive type or String.<br>
|
|
||||||
* Use {@link Component#getConfig()} or {@link ButtonPlugin#getIConfig()} then {@link IHaveConfig#getData(String, Object)} to get an instance.
|
|
||||||
*/
|
|
||||||
//@AllArgsConstructor(access = AccessLevel.PACKAGE)
|
|
||||||
public class ConfigData<T> {
|
|
||||||
private static final HashMap<Configuration, SaveTask> saveTasks = new HashMap<>();
|
|
||||||
/**
|
|
||||||
* May be null for testing
|
|
||||||
*/
|
|
||||||
private final ConfigurationSection config;
|
|
||||||
@Getter
|
|
||||||
@Setter(AccessLevel.PACKAGE)
|
|
||||||
private String path;
|
|
||||||
private final T def;
|
|
||||||
private final Object primitiveDef;
|
|
||||||
private final Runnable saveAction;
|
|
||||||
/**
|
|
||||||
* The parameter is of a primitive type as returned by {@link YamlConfiguration#get(String)}
|
|
||||||
*/
|
|
||||||
private Function<Object, T> getter;
|
|
||||||
/**
|
|
||||||
* The result should be a primitive type or string that can be retrieved correctly later
|
|
||||||
*/
|
|
||||||
private Function<T, Object> setter;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The config value should not change outside this instance
|
|
||||||
*/
|
|
||||||
private T value;
|
|
||||||
/**
|
|
||||||
* Whether the default value is saved in the yaml
|
|
||||||
*/
|
|
||||||
private boolean saved = false;
|
|
||||||
|
|
||||||
//This constructor is needed because it sets the getter and setter
|
|
||||||
ConfigData(ConfigurationSection config, String path, T def, Object primitiveDef, Function<Object, T> getter, Function<T, Object> setter, Runnable saveAction) {
|
|
||||||
this.config = config;
|
|
||||||
this.path = path;
|
|
||||||
this.def = def;
|
|
||||||
this.primitiveDef = primitiveDef;
|
|
||||||
this.getter = getter;
|
|
||||||
this.setter = setter;
|
|
||||||
this.saveAction = saveAction;
|
|
||||||
}
|
|
||||||
|
|
||||||
@java.beans.ConstructorProperties({"config", "path", "def", "primitiveDef", "saveAction"})
|
|
||||||
ConfigData(ConfigurationSection config, String path, T def, Object primitiveDef, Runnable saveAction) {
|
|
||||||
this.config = config;
|
|
||||||
this.path = path;
|
|
||||||
this.def = def;
|
|
||||||
this.primitiveDef = primitiveDef;
|
|
||||||
this.saveAction = saveAction;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String toString() {
|
|
||||||
return "ConfigData{" +
|
|
||||||
"path='" + path + '\'' +
|
|
||||||
", value=" + value +
|
|
||||||
'}';
|
|
||||||
}
|
|
||||||
|
|
||||||
@SuppressWarnings("unchecked")
|
|
||||||
public T get() {
|
|
||||||
if (value != null) return value; //Speed things up
|
|
||||||
Object val = config == null ? null : config.get(path); //config==null: testing
|
|
||||||
if (val == null) {
|
|
||||||
val = primitiveDef;
|
|
||||||
}
|
|
||||||
if (!saved && Objects.equals(val, primitiveDef)) { //String needs .equals()
|
|
||||||
if (def == null && config != null) //In Discord's case def may be null
|
|
||||||
config.set(path, primitiveDef);
|
|
||||||
else
|
|
||||||
set(def); //Save default value - def is always set
|
|
||||||
saved = true;
|
|
||||||
}
|
|
||||||
if (getter != null) {
|
|
||||||
T hmm = getter.apply(val);
|
|
||||||
if (hmm == null) hmm = def; //Set if the getter returned null
|
|
||||||
return hmm;
|
|
||||||
}
|
|
||||||
if (val instanceof Number && def != null)
|
|
||||||
val = ThorpeUtils.convertNumber((Number) val,
|
|
||||||
(Class<? extends Number>) def.getClass());
|
|
||||||
if (val instanceof List && def != null && def.getClass().isArray())
|
|
||||||
val = ((List<T>) val).toArray((T[]) Array.newInstance(def.getClass().getComponentType(), 0));
|
|
||||||
return value = (T) val; //Always cache, if not cached yet
|
|
||||||
}
|
|
||||||
|
|
||||||
public void set(T value) {
|
|
||||||
if (this instanceof ReadOnlyConfigData)
|
|
||||||
return; //Safety for Discord channel/role data
|
|
||||||
Object val;
|
|
||||||
if (setter != null && value != null)
|
|
||||||
val = setter.apply(value);
|
|
||||||
else val = value;
|
|
||||||
if (config != null) {
|
|
||||||
config.set(path, val);
|
|
||||||
if (!saveTasks.containsKey(config.getRoot())) {
|
|
||||||
synchronized (saveTasks) {
|
|
||||||
saveTasks.put(config.getRoot(), new SaveTask(Bukkit.getScheduler().runTaskLaterAsynchronously(MainPlugin.Instance, () -> {
|
|
||||||
synchronized (saveTasks) {
|
|
||||||
saveTasks.remove(config.getRoot());
|
|
||||||
saveAction.run();
|
|
||||||
}
|
|
||||||
}, 100), saveAction));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
this.value = value;
|
|
||||||
}
|
|
||||||
|
|
||||||
@AllArgsConstructor
|
|
||||||
private static class SaveTask {
|
|
||||||
BukkitTask task;
|
|
||||||
Runnable saveAction;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static boolean saveNow(Configuration config) {
|
|
||||||
SaveTask st = saveTasks.get(config);
|
|
||||||
if (st != null) {
|
|
||||||
st.task.cancel();
|
|
||||||
saveTasks.remove(config);
|
|
||||||
st.saveAction.run();
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,15 +0,0 @@
|
||||||
package buttondevteam.lib.architecture;
|
|
||||||
|
|
||||||
import org.bukkit.configuration.ConfigurationSection;
|
|
||||||
|
|
||||||
import java.util.function.Function;
|
|
||||||
|
|
||||||
public class ReadOnlyConfigData<T> extends ConfigData<T> {
|
|
||||||
ReadOnlyConfigData(ConfigurationSection config, String path, T def, Object primitiveDef, Function<Object, T> getter, Function<T, Object> setter, Runnable saveAction) {
|
|
||||||
super(config, path, def, primitiveDef, getter, setter, saveAction);
|
|
||||||
}
|
|
||||||
|
|
||||||
ReadOnlyConfigData(ConfigurationSection config, String path, T def, Object primitiveDef, Runnable saveAction) {
|
|
||||||
super(config, path, def, primitiveDef, saveAction);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,20 +0,0 @@
|
||||||
package buttondevteam.lib.chat;
|
|
||||||
|
|
||||||
import lombok.Getter;
|
|
||||||
import lombok.RequiredArgsConstructor;
|
|
||||||
|
|
||||||
@RequiredArgsConstructor
|
|
||||||
@Getter
|
|
||||||
public enum Color implements TellrawSerializableEnum {
|
|
||||||
Black("black", 0, 0, 0), DarkBlue("dark_blue", 0, 0, 170), DarkGreen("dark_green", 0, 170, 0), DarkAqua("dark_aqua",
|
|
||||||
0, 170, 170), DarkRed("dark_red", 170, 0, 0), DarkPurple("dark_purple", 0, 170, 0), Gold("gold", 255, 170,
|
|
||||||
0), Gray("gray", 170, 170, 170), DarkGray("dark_gray", 85, 85, 85), Blue("blue", 85, 85,
|
|
||||||
255), Green("green", 85, 255, 85), Aqua("aqua", 85, 255, 255), Red("red", 255, 85,
|
|
||||||
85), LightPurple("light_purple", 255, 85,
|
|
||||||
255), Yellow("yellow", 255, 255, 85), White("white", 255, 255, 255);
|
|
||||||
|
|
||||||
private final String name;
|
|
||||||
private final int red;
|
|
||||||
private final int green;
|
|
||||||
private final int blue;
|
|
||||||
}
|
|
|
@ -1,324 +0,0 @@
|
||||||
package buttondevteam.lib.chat;
|
|
||||||
|
|
||||||
import buttondevteam.core.MainPlugin;
|
|
||||||
import buttondevteam.lib.TBMCCoreAPI;
|
|
||||||
import buttondevteam.lib.ThorpeUtils;
|
|
||||||
import buttondevteam.lib.player.ChromaGamerBase;
|
|
||||||
import com.google.common.base.Defaults;
|
|
||||||
import com.google.common.primitives.Primitives;
|
|
||||||
import lombok.AllArgsConstructor;
|
|
||||||
import lombok.RequiredArgsConstructor;
|
|
||||||
import lombok.experimental.var;
|
|
||||||
import lombok.val;
|
|
||||||
import org.bukkit.Bukkit;
|
|
||||||
import org.bukkit.configuration.file.YamlConfiguration;
|
|
||||||
import org.bukkit.scheduler.BukkitTask;
|
|
||||||
|
|
||||||
import java.io.InputStreamReader;
|
|
||||||
import java.lang.annotation.ElementType;
|
|
||||||
import java.lang.annotation.Retention;
|
|
||||||
import java.lang.annotation.RetentionPolicy;
|
|
||||||
import java.lang.annotation.Target;
|
|
||||||
import java.lang.reflect.InvocationTargetException;
|
|
||||||
import java.lang.reflect.Method;
|
|
||||||
import java.text.NumberFormat;
|
|
||||||
import java.text.ParseException;
|
|
||||||
import java.util.*;
|
|
||||||
import java.util.function.Function;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The method name is the subcommand, use underlines (_) to add further subcommands.
|
|
||||||
* The args may be null if the conversion failed and it's optional.
|
|
||||||
*/
|
|
||||||
public abstract class Command2<TC extends ICommand2, TP extends Command2Sender> {
|
|
||||||
protected Command2() {
|
|
||||||
commandHelp.add("§6---- Commands ----");
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Parameters annotated with this receive all of the remaining arguments
|
|
||||||
*/
|
|
||||||
@Target(ElementType.PARAMETER)
|
|
||||||
@Retention(RetentionPolicy.RUNTIME)
|
|
||||||
public @interface TextArg {
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Methods annotated with this will be recognised as subcommands
|
|
||||||
*/
|
|
||||||
@Target(ElementType.METHOD)
|
|
||||||
@Retention(RetentionPolicy.RUNTIME)
|
|
||||||
public @interface Subcommand {
|
|
||||||
/**
|
|
||||||
* Allowed for OPs only by default
|
|
||||||
*/
|
|
||||||
String MOD_GROUP = "mod";
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Help text to show players. A usage message will be also shown below it.
|
|
||||||
*/
|
|
||||||
String[] helpText() default {};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The main permission which allows using this command (individual access can be still granted with "thorpe.command.X").
|
|
||||||
* Used to be "tbmc.admin". The {@link #MOD_GROUP} is provided to use with this.
|
|
||||||
*/
|
|
||||||
String permGroup() default ""; //TODO
|
|
||||||
}
|
|
||||||
|
|
||||||
@Target(ElementType.PARAMETER)
|
|
||||||
@Retention(RetentionPolicy.RUNTIME)
|
|
||||||
public @interface OptionalArg {
|
|
||||||
}
|
|
||||||
|
|
||||||
@AllArgsConstructor
|
|
||||||
protected static class SubcommandData<T extends ICommand2> {
|
|
||||||
public final Method method;
|
|
||||||
public final T command;
|
|
||||||
public String[] helpText;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected static class SubcommandHelpData<T extends ICommand2> extends SubcommandData<T> {
|
|
||||||
private final TreeSet<String> ht = new TreeSet<>();
|
|
||||||
private BukkitTask task;
|
|
||||||
|
|
||||||
public SubcommandHelpData(Method method, T command, String[] helpText) {
|
|
||||||
super(method, command, helpText);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void addSubcommand(String command) {
|
|
||||||
ht.add(command);
|
|
||||||
if (task == null)
|
|
||||||
task = Bukkit.getScheduler().runTask(MainPlugin.Instance, () -> {
|
|
||||||
helpText = new String[ht.size() + 1]; //This will only run after the server is started List<E> list = new ArrayList<E>(size());
|
|
||||||
helpText[0] = "§6---- Subcommands ----"; //TODO: There may be more to the help text
|
|
||||||
int i = 1;
|
|
||||||
for (Iterator<String> iterator = ht.iterator();
|
|
||||||
iterator.hasNext() && i < helpText.length; i++) {
|
|
||||||
String e = iterator.next();
|
|
||||||
helpText[i] = e;
|
|
||||||
}
|
|
||||||
task = null; //Run again, if needed
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@RequiredArgsConstructor
|
|
||||||
protected static class ParamConverter<T> {
|
|
||||||
public final Function<String, T> converter;
|
|
||||||
public final String errormsg;
|
|
||||||
}
|
|
||||||
|
|
||||||
private HashMap<String, SubcommandData<TC>> subcommands = new HashMap<>();
|
|
||||||
private HashMap<Class<?>, ParamConverter<?>> paramConverters = new HashMap<>();
|
|
||||||
|
|
||||||
private ArrayList<String> commandHelp = new ArrayList<>(); //Mainly needed by Discord
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Adds a param converter that obtains a specific object from a string parameter.
|
|
||||||
* The converter may return null.
|
|
||||||
*
|
|
||||||
* @param cl The class of the result object
|
|
||||||
* @param converter The converter to use
|
|
||||||
* @param <T> The type of the result
|
|
||||||
*/
|
|
||||||
public <T> void addParamConverter(Class<T> cl, Function<String, T> converter, String errormsg) {
|
|
||||||
paramConverters.put(cl, new ParamConverter<>(converter, errormsg));
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean handleCommand(TP sender, String commandline) throws Exception {
|
|
||||||
for (int i = commandline.length(); i != -1; i = commandline.lastIndexOf(' ', i - 1)) {
|
|
||||||
String subcommand = commandline.substring(0, i).toLowerCase();
|
|
||||||
SubcommandData<TC> sd = subcommands.get(subcommand); //O(1)
|
|
||||||
if (sd == null) continue;
|
|
||||||
if (sd.method == null || sd.command == null) { //Main command not registered, but we have subcommands
|
|
||||||
sender.sendMessage(sd.helpText);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
if (!hasPermission(sender, sd.command, sd.method)) {
|
|
||||||
sender.sendMessage("§cYou don't have permission to use this command");
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
val params = new ArrayList<Object>(sd.method.getParameterCount());
|
|
||||||
int j = subcommand.length(), pj;
|
|
||||||
Class<?>[] parameterTypes = sd.method.getParameterTypes();
|
|
||||||
if (parameterTypes.length == 0)
|
|
||||||
throw new Exception("No sender parameter for method '" + sd.method + "'");
|
|
||||||
val sendertype = parameterTypes[0];
|
|
||||||
final ChromaGamerBase cg;
|
|
||||||
if (sendertype.isAssignableFrom(sender.getClass()))
|
|
||||||
params.add(sender); //The command either expects a CommandSender or it is a Player, or some other expected type
|
|
||||||
else if (sender instanceof Command2MCSender
|
|
||||||
&& sendertype.isAssignableFrom(((Command2MCSender) sender).getSender().getClass()))
|
|
||||||
params.add(((Command2MCSender) sender).getSender());
|
|
||||||
else if (ChromaGamerBase.class.isAssignableFrom(sendertype)
|
|
||||||
&& sender instanceof Command2MCSender
|
|
||||||
&& (cg = ChromaGamerBase.getFromSender(((Command2MCSender) sender).getSender())) != null
|
|
||||||
&& cg.getClass() == sendertype) //The command expects a user of our system
|
|
||||||
params.add(cg);
|
|
||||||
else {
|
|
||||||
sender.sendMessage("§cYou need to be a " + sendertype.getSimpleName() + " to use this command.");
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
val paramArr = sd.method.getParameters();
|
|
||||||
for (int i1 = 1; i1 < parameterTypes.length; i1++) {
|
|
||||||
Class<?> cl = parameterTypes[i1];
|
|
||||||
pj = j + 1; //Start index
|
|
||||||
if (pj == commandline.length() + 1) { //No param given
|
|
||||||
if (paramArr[i1].isAnnotationPresent(OptionalArg.class)) {
|
|
||||||
if (cl.isPrimitive())
|
|
||||||
params.add(Defaults.defaultValue(cl));
|
|
||||||
else if (Number.class.isAssignableFrom(cl)
|
|
||||||
|| Number.class.isAssignableFrom(cl))
|
|
||||||
params.add(Defaults.defaultValue(Primitives.unwrap(cl)));
|
|
||||||
else
|
|
||||||
params.add(null);
|
|
||||||
continue; //Fill the remaining params with nulls
|
|
||||||
} else {
|
|
||||||
sender.sendMessage(sd.helpText); //Required param missing
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (paramArr[i1].isVarArgs()) {
|
|
||||||
params.add(commandline.substring(j + 1).split(" +"));
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
j = commandline.indexOf(' ', j + 1); //End index
|
|
||||||
if (j == -1 || paramArr[i1].isAnnotationPresent(TextArg.class)) //Last parameter
|
|
||||||
j = commandline.length();
|
|
||||||
String param = commandline.substring(pj, j);
|
|
||||||
if (cl == String.class) {
|
|
||||||
params.add(param);
|
|
||||||
continue;
|
|
||||||
} else if (Number.class.isAssignableFrom(cl) || cl.isPrimitive()) {
|
|
||||||
try {
|
|
||||||
//noinspection unchecked
|
|
||||||
Number n = ThorpeUtils.convertNumber(NumberFormat.getInstance().parse(param), (Class<? extends Number>) cl);
|
|
||||||
params.add(n);
|
|
||||||
} catch (ParseException e) {
|
|
||||||
sender.sendMessage("§c'" + param + "' is not a number.");
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
val conv = paramConverters.get(cl);
|
|
||||||
if (conv == null)
|
|
||||||
throw new Exception("No suitable converter found for parameter type '" + cl.getCanonicalName() + "' for command '" + sd.method.toString() + "'");
|
|
||||||
val cparam = conv.converter.apply(param);
|
|
||||||
if (cparam == null) {
|
|
||||||
sender.sendMessage(conv.errormsg); //Param conversion failed - ex. plugin not found
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
params.add(cparam);
|
|
||||||
}
|
|
||||||
try {
|
|
||||||
val ret = sd.method.invoke(sd.command, params.toArray()); //I FORGOT TO TURN IT INTO AN ARRAY (for a long time)
|
|
||||||
if (ret instanceof Boolean) {
|
|
||||||
if (!(boolean) ret) //Show usage
|
|
||||||
sender.sendMessage(sd.helpText);
|
|
||||||
} else if (ret != null)
|
|
||||||
throw new Exception("Wrong return type! Must return a boolean or void. Return value: " + ret);
|
|
||||||
return true; //We found a method
|
|
||||||
} catch (InvocationTargetException e) {
|
|
||||||
TBMCCoreAPI.SendException("An error occurred in a command handler!", e.getCause());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false; //Didn't handle
|
|
||||||
} //TODO: Add to the help
|
|
||||||
|
|
||||||
public abstract void registerCommand(TC command);
|
|
||||||
|
|
||||||
protected void registerCommand(TC command, char commandChar) {
|
|
||||||
val path = command.getCommandPath();
|
|
||||||
int x = path.indexOf(' ');
|
|
||||||
val mainPath = commandChar + path.substring(0, x == -1 ? path.length() : x);
|
|
||||||
//var scmdmap = subcommandStrings.computeIfAbsent(mainPath, k -> new HashSet<>()); //Used to display subcommands
|
|
||||||
val scmdHelpList = new ArrayList<String>();
|
|
||||||
Method mainMethod = null;
|
|
||||||
boolean nosubs = true;
|
|
||||||
boolean isSubcommand = x != -1;
|
|
||||||
try { //Register the default handler first so it can be reliably overwritten
|
|
||||||
mainMethod = command.getClass().getMethod("def", Command2Sender.class, String.class);
|
|
||||||
val cc = command.getClass().getAnnotation(CommandClass.class);
|
|
||||||
var ht = cc == null || isSubcommand ? new String[0] : cc.helpText(); //If it's not the main command, don't add it
|
|
||||||
if (ht.length > 0)
|
|
||||||
ht[0] = "§6---- " + ht[0] + " ----";
|
|
||||||
scmdHelpList.addAll(Arrays.asList(ht));
|
|
||||||
if (!isSubcommand)
|
|
||||||
scmdHelpList.add("§6Subcommands:");
|
|
||||||
if (!commandHelp.contains(mainPath))
|
|
||||||
commandHelp.add(mainPath);
|
|
||||||
} catch (Exception e) {
|
|
||||||
TBMCCoreAPI.SendException("Could not register default handler for command /" + path, e);
|
|
||||||
}
|
|
||||||
for (val method : command.getClass().getMethods()) {
|
|
||||||
val ann = method.getAnnotation(Subcommand.class);
|
|
||||||
if (ann == null) continue; //Don't call the method on non-subcommands because they're not in the yaml
|
|
||||||
var ht = command.getHelpText(method, ann);
|
|
||||||
if (ht != null) {
|
|
||||||
val subcommand = commandChar + path + //Add command path (class name by default)
|
|
||||||
(method.getName().equals("def") ? "" : " " + method.getName().replace('_', ' ').toLowerCase()); //Add method name, unless it's 'def'
|
|
||||||
ht = getHelpText(method, ht, subcommand);
|
|
||||||
subcommands.put(subcommand, new SubcommandData<>(method, command, ht)); //Result of the above (def) is that it will show the help text
|
|
||||||
scmdHelpList.add(subcommand);
|
|
||||||
nosubs = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (nosubs && scmdHelpList.size() > 0)
|
|
||||||
scmdHelpList.remove(scmdHelpList.size() - 1); //Remove Subcommands header
|
|
||||||
if (mainMethod != null && !subcommands.containsKey(commandChar + path)) //Command specified by the class
|
|
||||||
subcommands.put(commandChar + path, new SubcommandData<>(mainMethod, command, scmdHelpList.toArray(new String[0])));
|
|
||||||
if (mainMethod != null && !mainPath.equals(commandChar + path)) { //Main command, typically the same as the above
|
|
||||||
if (isSubcommand) { //The class itself is a subcommand
|
|
||||||
val scmd = subcommands.computeIfAbsent(mainPath, p -> new SubcommandData<>(null, null, new String[]{"§6---- Subcommands ----"}));
|
|
||||||
val scmdHelp = Arrays.copyOf(scmd.helpText, scmd.helpText.length + scmdHelpList.size());
|
|
||||||
for (int i = 0; i < scmdHelpList.size(); i++)
|
|
||||||
scmdHelp[scmd.helpText.length + i] = scmdHelpList.get(i);
|
|
||||||
scmd.helpText = scmdHelp;
|
|
||||||
} else if (!subcommands.containsKey(mainPath))
|
|
||||||
subcommands.put(mainPath, new SubcommandData<>(null, null, scmdHelpList.toArray(new String[0])));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private String[] getHelpText(Method method, String[] ht, String subcommand) {
|
|
||||||
val str = method.getDeclaringClass().getResourceAsStream("/commands.yml");
|
|
||||||
if (str == null)
|
|
||||||
TBMCCoreAPI.SendException("Error while getting command data!", new Exception("Resource not found!"));
|
|
||||||
else {
|
|
||||||
if (ht.length > 0)
|
|
||||||
ht[0] = "§6---- " + ht[0] + " ----";
|
|
||||||
YamlConfiguration yc = YamlConfiguration.loadConfiguration(new InputStreamReader(str)); //Generated by ButtonProcessor
|
|
||||||
val ccs = yc.getConfigurationSection(method.getDeclaringClass().getCanonicalName());
|
|
||||||
if (ccs != null) {
|
|
||||||
val cs = ccs.getConfigurationSection(method.getName());
|
|
||||||
if (cs != null) {
|
|
||||||
val mname = cs.getString("method");
|
|
||||||
val params = cs.getString("params");
|
|
||||||
//val goodname = method.getName() + "(" + Arrays.stream(method.getGenericParameterTypes()).map(cl -> cl.getTypeName()).collect(Collectors.joining(",")) + ")";
|
|
||||||
int i = mname.indexOf('('); //Check only the name - the whole method is still stored for backwards compatibility and in case it may be useful
|
|
||||||
if (i != -1 && method.getName().equals(mname.substring(0, i)) && params != null) {
|
|
||||||
String[] both = Arrays.copyOf(ht, ht.length + 1);
|
|
||||||
both[ht.length] = "§6Usage:§r " + subcommand + " " + params;
|
|
||||||
ht = both;
|
|
||||||
} else
|
|
||||||
TBMCCoreAPI.SendException("Error while getting command data for " + method + "!", new Exception("Method '" + method.toString() + "' != " + mname + " or params is " + params));
|
|
||||||
} else
|
|
||||||
TBMCCoreAPI.SendException("Error while getting command data for " + method + "!", new Exception("cs is " + cs));
|
|
||||||
} else
|
|
||||||
TBMCCoreAPI.SendException("Error while getting command data for " + method + "!", new Exception("ccs is " + ccs + " - class: " + method.getDeclaringClass().getCanonicalName()));
|
|
||||||
}
|
|
||||||
return ht;
|
|
||||||
}
|
|
||||||
|
|
||||||
public abstract boolean hasPermission(TP sender, TC command, Method subcommand);
|
|
||||||
|
|
||||||
public String[] getCommandsText() {
|
|
||||||
return commandHelp.toArray(new String[0]);
|
|
||||||
}
|
|
||||||
|
|
||||||
public String[] getHelpText(String path) {
|
|
||||||
val scmd = subcommands.get(path);
|
|
||||||
if (scmd == null) return null;
|
|
||||||
return scmd.helpText;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,112 +0,0 @@
|
||||||
package buttondevteam.lib.chat;
|
|
||||||
|
|
||||||
import buttondevteam.core.MainPlugin;
|
|
||||||
import lombok.experimental.var;
|
|
||||||
import lombok.val;
|
|
||||||
import org.bukkit.Bukkit;
|
|
||||||
import org.bukkit.OfflinePlayer;
|
|
||||||
import org.bukkit.command.ConsoleCommandSender;
|
|
||||||
import org.bukkit.permissions.Permission;
|
|
||||||
import org.bukkit.permissions.PermissionDefault;
|
|
||||||
|
|
||||||
import java.lang.annotation.Annotation;
|
|
||||||
import java.lang.reflect.Method;
|
|
||||||
import java.util.UUID;
|
|
||||||
import java.util.function.Function;
|
|
||||||
|
|
||||||
public class Command2MC extends Command2<ICommand2MC, Command2MCSender> {
|
|
||||||
@Override
|
|
||||||
public void registerCommand(ICommand2MC command) {
|
|
||||||
super.registerCommand(command, '/');
|
|
||||||
var perm = "thorpe.command." + command.getCommandPath().replace(' ', '.');
|
|
||||||
if (Bukkit.getPluginManager().getPermission(perm) == null) //Check needed for plugin reset
|
|
||||||
Bukkit.getPluginManager().addPermission(new Permission(perm,
|
|
||||||
modOnly(command) ? PermissionDefault.OP : PermissionDefault.TRUE)); //Allow commands by default, unless it's mod only - TODO: Test
|
|
||||||
for (val method : command.getClass().getMethods()) {
|
|
||||||
if (!method.isAnnotationPresent(Subcommand.class)) continue;
|
|
||||||
String pg = permGroup(command, method);
|
|
||||||
if (pg.length() == 0) continue;
|
|
||||||
perm = "thorpe." + pg;
|
|
||||||
if (Bukkit.getPluginManager().getPermission(perm) == null) //It may occur multiple times
|
|
||||||
Bukkit.getPluginManager().addPermission(new Permission(perm,
|
|
||||||
//pg.equals(Subcommand.MOD_GROUP) ? PermissionDefault.OP : PermissionDefault.TRUE)); //Allow commands by default, unless it's mod only
|
|
||||||
PermissionDefault.OP)); //Do not allow any commands that belong to a group
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean hasPermission(Command2MCSender sender, ICommand2MC command, Method method) {
|
|
||||||
if (sender.getSender() instanceof ConsoleCommandSender) return true; //Always allow the console
|
|
||||||
String pg;
|
|
||||||
boolean p = true;
|
|
||||||
String[] perms = {
|
|
||||||
"thorpe.command." + command.getCommandPath().replace(' ', '.'),
|
|
||||||
(pg = permGroup(command, method)).length() > 0 ? "thorpe." + pg : null,
|
|
||||||
modOnly(command) ? "tbmc.admin" : null
|
|
||||||
};
|
|
||||||
for (String perm : perms) {
|
|
||||||
if (perm != null) {
|
|
||||||
if (p) { //Use OfflinePlayer to avoid fetching player data
|
|
||||||
if (sender.getSender() instanceof OfflinePlayer)
|
|
||||||
p = MainPlugin.permission.playerHas(null, (OfflinePlayer) sender.getSender(), perm);
|
|
||||||
else
|
|
||||||
p = MainPlugin.permission.playerHas(null, Bukkit.getOfflinePlayer(new UUID(0, 0)), perm);
|
|
||||||
} else break; //If any of the permissions aren't granted then don't allow
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return p;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns true if this class or <u>any</u> of the superclasses are mod only.
|
|
||||||
*
|
|
||||||
* @param command The command to check
|
|
||||||
* @return Whether the command is mod only
|
|
||||||
*/
|
|
||||||
private boolean modOnly(ICommand2MC command) {
|
|
||||||
return getAnnForValue(command.getClass(), CommandClass.class, CommandClass::modOnly, false);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns true if this class or <u>any</u> of the superclasses are mod only.
|
|
||||||
*
|
|
||||||
* @param method The subcommand to check
|
|
||||||
* @return The permission group for the subcommand or empty string
|
|
||||||
*/
|
|
||||||
private String permGroup(ICommand2MC command, Method method) {
|
|
||||||
val sc = method.getAnnotation(Subcommand.class);
|
|
||||||
if (sc != null && sc.permGroup().length() > 0) {
|
|
||||||
return sc.permGroup();
|
|
||||||
}
|
|
||||||
return getAnnForValue(command.getClass(), CommandClass.class, CommandClass::permGroup, "");
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Loops until it finds a value that is <b>not</b> the same as def
|
|
||||||
*
|
|
||||||
* @param sourceCl The class which has the annotation
|
|
||||||
* @param annCl The annotation to get
|
|
||||||
* @param annMethod The annotation method to check
|
|
||||||
* @param def The value to ignore when looking for the result
|
|
||||||
* @param <T> The annotation type
|
|
||||||
* @param <V> The type of the value
|
|
||||||
* @return The value returned by the first superclass or def
|
|
||||||
*/
|
|
||||||
private <T extends Annotation, V> V getAnnForValue(Class<?> sourceCl, Class<T> annCl, Function<T, V> annMethod, V def) {
|
|
||||||
for (Class<?> cl = sourceCl; cl != null; cl = cl.getSuperclass()) {
|
|
||||||
val cc = cl.getAnnotation(annCl);
|
|
||||||
V r;
|
|
||||||
if (cc != null && (r = annMethod.apply(cc)) != def) return r;
|
|
||||||
}
|
|
||||||
return def;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Automatically colors the message red.
|
|
||||||
* {@see super#addParamConverter}
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
public <T> void addParamConverter(Class<T> cl, Function<String, T> converter, String errormsg) {
|
|
||||||
super.addParamConverter(cl, converter, "§c" + errormsg);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,9 +0,0 @@
|
||||||
package buttondevteam.lib.chat;
|
|
||||||
|
|
||||||
import buttondevteam.lib.architecture.ButtonPlugin;
|
|
||||||
|
|
||||||
public abstract class ICommand2MC extends ICommand2<Command2MCSender> {
|
|
||||||
public ICommand2MC() {
|
|
||||||
super(ButtonPlugin.getCommand2MC());
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,29 +0,0 @@
|
||||||
package buttondevteam.lib.chat;
|
|
||||||
|
|
||||||
import buttondevteam.lib.TBMCCoreAPI;
|
|
||||||
import org.bukkit.command.CommandSender;
|
|
||||||
import org.bukkit.entity.Player;
|
|
||||||
|
|
||||||
public abstract class OptionallyPlayerCommandBase extends TBMCCommandBase {
|
|
||||||
public boolean OnCommand(Player player, String alias, String[] args) {
|
|
||||||
if (getClass().isAnnotationPresent(OptionallyPlayerCommandClass.class)
|
|
||||||
&& getClass().getAnnotation(OptionallyPlayerCommandClass.class).playerOnly())
|
|
||||||
TBMCCoreAPI.SendException("Error while executing command " + getClass().getSimpleName() + "!",
|
|
||||||
new Exception(
|
|
||||||
"The PlayerCommand annotation is present and set to playerOnly but the Player overload isn't overriden!"));
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean OnCommand(CommandSender sender, String alias, String[] args) {
|
|
||||||
if (sender instanceof Player)
|
|
||||||
return OnCommand((Player) sender, alias, args);
|
|
||||||
if (!getClass().isAnnotationPresent(OptionallyPlayerCommandClass.class)
|
|
||||||
|| !getClass().getAnnotation(OptionallyPlayerCommandClass.class).playerOnly())
|
|
||||||
TBMCCoreAPI.SendException("Error while executing command " + getClass().getSimpleName() + "!",
|
|
||||||
new Exception(
|
|
||||||
"Command class doesn't override the CommandSender overload and no PlayerCommandClass annotation is present or playerOnly is false!"));
|
|
||||||
sender.sendMessage("§cYou need to be a player to use this command.");
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,16 +0,0 @@
|
||||||
package buttondevteam.lib.chat;
|
|
||||||
|
|
||||||
import java.lang.annotation.*;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Only needed to use with {@link OptionallyPlayerCommandBase} command classes
|
|
||||||
*
|
|
||||||
* @author NorbiPeti
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
@Retention(RetentionPolicy.RUNTIME)
|
|
||||||
@Target(ElementType.TYPE)
|
|
||||||
@Inherited
|
|
||||||
public @interface OptionallyPlayerCommandClass {
|
|
||||||
boolean playerOnly();
|
|
||||||
}
|
|
|
@ -1,16 +0,0 @@
|
||||||
package buttondevteam.lib.chat;
|
|
||||||
|
|
||||||
import org.bukkit.command.CommandSender;
|
|
||||||
import org.bukkit.entity.Player;
|
|
||||||
|
|
||||||
public abstract class PlayerCommandBase extends TBMCCommandBase {
|
|
||||||
public abstract boolean OnCommand(Player player, String alias, String[] args);
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public final boolean OnCommand(CommandSender sender, String alias, String[] args) {
|
|
||||||
if (sender instanceof Player)
|
|
||||||
return OnCommand((Player) sender, alias, args);
|
|
||||||
sender.sendMessage("§cYou need to be a player to use this command.");
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,342 +0,0 @@
|
||||||
package buttondevteam.lib.chat;
|
|
||||||
|
|
||||||
import buttondevteam.core.CommandCaller;
|
|
||||||
import buttondevteam.core.MainPlugin;
|
|
||||||
import buttondevteam.core.component.channel.Channel;
|
|
||||||
import buttondevteam.core.component.channel.Channel.RecipientTestResult;
|
|
||||||
import buttondevteam.lib.TBMCChatEvent;
|
|
||||||
import buttondevteam.lib.TBMCChatPreprocessEvent;
|
|
||||||
import buttondevteam.lib.TBMCCoreAPI;
|
|
||||||
import buttondevteam.lib.TBMCSystemChatEvent;
|
|
||||||
import buttondevteam.lib.architecture.Component;
|
|
||||||
import lombok.val;
|
|
||||||
import org.bukkit.Bukkit;
|
|
||||||
import org.bukkit.command.CommandSender;
|
|
||||||
import org.bukkit.entity.Player;
|
|
||||||
import org.bukkit.plugin.java.JavaPlugin;
|
|
||||||
import org.reflections.Reflections;
|
|
||||||
import org.reflections.scanners.SubTypesScanner;
|
|
||||||
import org.reflections.util.ClasspathHelper;
|
|
||||||
import org.reflections.util.ConfigurationBuilder;
|
|
||||||
|
|
||||||
import java.lang.reflect.Modifier;
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.Arrays;
|
|
||||||
import java.util.HashMap;
|
|
||||||
import java.util.Map.Entry;
|
|
||||||
import java.util.Set;
|
|
||||||
import java.util.function.Consumer;
|
|
||||||
|
|
||||||
public class TBMCChatAPI {
|
|
||||||
|
|
||||||
private static final HashMap<String, TBMCCommandBase> commands = new HashMap<>();
|
|
||||||
|
|
||||||
public static HashMap<String, TBMCCommandBase> GetCommands() {
|
|
||||||
return commands;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns messages formatted for Minecraft chat listing the subcommands of the command.
|
|
||||||
*
|
|
||||||
* @param command
|
|
||||||
* The command which we want the subcommands of
|
|
||||||
* @param sender
|
|
||||||
* The sender for permissions
|
|
||||||
* @return The subcommands
|
|
||||||
*/
|
|
||||||
public static String[] GetSubCommands(TBMCCommandBase command, CommandSender sender) {
|
|
||||||
return GetSubCommands(command.GetCommandPath(), sender);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns messages formatted for Minecraft chat listing the subcommands of the command.<br>
|
|
||||||
* Returns a header if subcommands were found, otherwise returns an empty array.
|
|
||||||
*
|
|
||||||
* @param command
|
|
||||||
* The command which we want the subcommands of
|
|
||||||
* @param sender
|
|
||||||
* The sender for permissions
|
|
||||||
* @return The subcommands
|
|
||||||
*/
|
|
||||||
public static String[] GetSubCommands(String command, CommandSender sender) {
|
|
||||||
ArrayList<String> cmds = new ArrayList<String>();
|
|
||||||
Consumer<String> addToCmds = cmd -> {
|
|
||||||
if (cmds.size() == 0)
|
|
||||||
cmds.add("§6---- Subcommands ----");
|
|
||||||
cmds.add(cmd);
|
|
||||||
};
|
|
||||||
for (Entry<String, TBMCCommandBase> cmd : TBMCChatAPI.GetCommands().entrySet()) {
|
|
||||||
if (cmd.getKey().startsWith(command + " ")) {
|
|
||||||
if (cmd.getValue().isPlayerOnly() && !(sender instanceof Player))
|
|
||||||
continue;
|
|
||||||
if (cmd.getValue().isModOnly() && (MainPlugin.permission != null ? !MainPlugin.permission.has(sender, "tbmc.admin") : !sender.isOp()))
|
|
||||||
continue;
|
|
||||||
int ind = cmd.getKey().indexOf(' ', command.length() + 2);
|
|
||||||
if (ind >= 0) {
|
|
||||||
String newcmd = cmd.getKey().substring(0, ind);
|
|
||||||
if (!cmds.contains("/" + newcmd))
|
|
||||||
addToCmds.accept("/" + newcmd);
|
|
||||||
} else
|
|
||||||
addToCmds.accept("/" + cmd.getKey());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return cmds.toArray(new String[0]); //Apparently it's faster to use an empty array in modern Java
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* <p>
|
|
||||||
* This method adds a plugin's commands to help and sets their executor.
|
|
||||||
* </p>
|
|
||||||
* <p>
|
|
||||||
* </p>
|
|
||||||
* <b>The command classes have to have a constructor each with no parameters</b>
|
|
||||||
* <p>
|
|
||||||
* The <u>command must be registered</u> in the caller plugin's plugin.yml. Otherwise the plugin will output a messsage to console.
|
|
||||||
* </p>
|
|
||||||
* <p>
|
|
||||||
* <i>Using this method after the server is done loading will have no effect.</i>
|
|
||||||
* </p>
|
|
||||||
*
|
|
||||||
* @param plugin
|
|
||||||
* The caller plugin
|
|
||||||
* @param acmdclass
|
|
||||||
* A command's class to get the package name for commands. The provided class's package and subpackages are scanned for commands.
|
|
||||||
*/
|
|
||||||
public static synchronized void AddCommands(JavaPlugin plugin, Class<? extends TBMCCommandBase> acmdclass) {
|
|
||||||
plugin.getLogger().info("Registering commands from " + acmdclass.getPackage().getName());
|
|
||||||
Reflections rf = new Reflections(new ConfigurationBuilder()
|
|
||||||
.setUrls(ClasspathHelper.forPackage(acmdclass.getPackage().getName(),
|
|
||||||
plugin.getClass().getClassLoader()))
|
|
||||||
.addUrls(
|
|
||||||
ClasspathHelper.forClass(OptionallyPlayerCommandBase.class,
|
|
||||||
OptionallyPlayerCommandBase.class.getClassLoader()),
|
|
||||||
ClasspathHelper.forClass(PlayerCommandBase.class, PlayerCommandBase.class.getClassLoader())) // http://stackoverflow.com/questions/12917417/using-reflections-for-finding-the-transitive-subtypes-of-a-class-when-not-all
|
|
||||||
.addClassLoader(plugin.getClass().getClassLoader()).addScanners(new SubTypesScanner()));
|
|
||||||
Set<Class<? extends TBMCCommandBase>> cmds = rf.getSubTypesOf(TBMCCommandBase.class);
|
|
||||||
for (Class<? extends TBMCCommandBase> cmd : cmds) {
|
|
||||||
try {
|
|
||||||
if (!cmd.getPackage().getName().startsWith(acmdclass.getPackage().getName()))
|
|
||||||
continue; // It keeps including the commands from here
|
|
||||||
if (Modifier.isAbstract(cmd.getModifiers()))
|
|
||||||
continue;
|
|
||||||
TBMCCommandBase c = cmd.newInstance();
|
|
||||||
c.plugin = plugin;
|
|
||||||
CommandCaller.RegisterCommand(c); //Will check for nulls
|
|
||||||
commands.put(c.GetCommandPath(), c);
|
|
||||||
} catch (Exception e) {
|
|
||||||
TBMCCoreAPI.SendException("An error occured while registering command " + cmd.getName(), e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* <p>
|
|
||||||
* This method adds a plugin's command to help and sets it's executor. They will be automatically unregistered on plugin disable.
|
|
||||||
* </p>
|
|
||||||
* <p>
|
|
||||||
* The <u>command must be registered</u> in the caller plugin's plugin.yml. Otherwise the plugin will output a messsage to console.
|
|
||||||
* </p>
|
|
||||||
* <p>
|
|
||||||
* <i>Using this method after the server is done loading will have no effect.</i>
|
|
||||||
* </p>
|
|
||||||
*
|
|
||||||
* @param plugin
|
|
||||||
* The caller plugin
|
|
||||||
* @param thecmdclass
|
|
||||||
* The command's class to create it (because why let you create the command class)
|
|
||||||
*/
|
|
||||||
public static void AddCommand(JavaPlugin plugin, Class<? extends TBMCCommandBase> thecmdclass, Object... params) {
|
|
||||||
// plugin.getLogger().info("Registering command " + thecmdclass.getSimpleName() + " for " + plugin.getName());
|
|
||||||
try {
|
|
||||||
TBMCCommandBase c;
|
|
||||||
if (params.length > 0)
|
|
||||||
c = thecmdclass.getConstructor(Arrays.stream(params).map(Object::getClass).toArray(Class[]::new))
|
|
||||||
.newInstance(params);
|
|
||||||
else
|
|
||||||
c = thecmdclass.newInstance();
|
|
||||||
c.plugin = plugin;
|
|
||||||
CommandCaller.RegisterCommand(c); //Will check for nulls
|
|
||||||
commands.put(c.GetCommandPath(), c);
|
|
||||||
} catch (Exception e) {
|
|
||||||
TBMCCoreAPI.SendException("An error occured while registering command " + thecmdclass.getSimpleName(), e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* <p>
|
|
||||||
* This method adds a plugin's command to help and sets its executor. They will be automatically unregistered on plugin disable.
|
|
||||||
* </p>
|
|
||||||
* <p>
|
|
||||||
* The <u>command must be registered</u> in the caller plugin's plugin.yml. Otherwise the plugin will output a message to console.
|
|
||||||
* </p>
|
|
||||||
* <p>
|
|
||||||
* <i>Using this method after the server is done loading will have no effect.</i>
|
|
||||||
* </p>
|
|
||||||
*
|
|
||||||
* @param plugin
|
|
||||||
* The caller plugin
|
|
||||||
* @param cmd
|
|
||||||
* The command to add
|
|
||||||
*/
|
|
||||||
public static void AddCommand(JavaPlugin plugin, TBMCCommandBase cmd) {
|
|
||||||
try {
|
|
||||||
if (plugin == null) throw new IllegalArgumentException("The plugin is null!");
|
|
||||||
if (cmd == null) throw new IllegalArgumentException("The command is null!");
|
|
||||||
cmd.plugin = plugin;
|
|
||||||
CommandCaller.RegisterCommand(cmd); //Checks for other nulls
|
|
||||||
commands.put(cmd.GetCommandPath(), cmd);
|
|
||||||
} catch (Exception e) {
|
|
||||||
TBMCCoreAPI.SendException("An error occured while registering command " + (cmd == null ? "n u l l" : cmd.GetCommandPath()), e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* <p>
|
|
||||||
* This method adds a plugin's command to help and sets its executor. They will be automatically unregistered on component disable.
|
|
||||||
* </p>
|
|
||||||
* <p>
|
|
||||||
* The <u>command must be registered</u> in the caller plugin's plugin.yml. Otherwise the plugin will output a message to console.
|
|
||||||
* </p>
|
|
||||||
* <p>
|
|
||||||
* <i>Using this method after the server is done loading will have no effect.</i>
|
|
||||||
* </p>
|
|
||||||
*
|
|
||||||
* @param component The caller component
|
|
||||||
* @param cmd The command to add
|
|
||||||
*/
|
|
||||||
public static void AddCommand(Component component, TBMCCommandBase cmd) {
|
|
||||||
try {
|
|
||||||
if (component == null) throw new IllegalArgumentException("The component is null!");
|
|
||||||
if (cmd == null) throw new IllegalArgumentException("The command is null!");
|
|
||||||
cmd.plugin = component.getPlugin();
|
|
||||||
cmd.component = component;
|
|
||||||
CommandCaller.RegisterCommand(cmd); //Checks for other nulls
|
|
||||||
commands.put(cmd.GetCommandPath(), cmd);
|
|
||||||
} catch (Exception e) {
|
|
||||||
TBMCCoreAPI.SendException("An error occured while registering command " + (cmd == null ? "n u l l" : cmd.GetCommandPath()), e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Removes all commands from the plugin
|
|
||||||
*
|
|
||||||
* @param plugin The plugin to remove commands from
|
|
||||||
*/
|
|
||||||
public static void RemoveCommands(JavaPlugin plugin) {
|
|
||||||
commands.values().removeIf(c -> {
|
|
||||||
try {
|
|
||||||
if (c.plugin == plugin) {
|
|
||||||
CommandCaller.UnregisterCommand(c);
|
|
||||||
return true; //Remove
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
} catch (Exception e) {
|
|
||||||
TBMCCoreAPI.SendException("An error occured while unregistering commands for " + plugin.getName(), e);
|
|
||||||
return true; //Remove if it couldn't get the plugin command
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Removes all commands from the component
|
|
||||||
*
|
|
||||||
* @param component The component to remove commands from
|
|
||||||
*/
|
|
||||||
public static void RemoveCommands(Component component) {
|
|
||||||
commands.values().removeIf(c -> {
|
|
||||||
try {
|
|
||||||
if (c.component == component) {
|
|
||||||
CommandCaller.UnregisterCommand(c);
|
|
||||||
return true; //Remove
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
} catch (Exception e) {
|
|
||||||
TBMCCoreAPI.SendException("An error occured while unregistering commands for " + component.getClass().getSimpleName(), e);
|
|
||||||
return true; //Remove if it couldn't get the plugin command
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Sends a chat message to Minecraft. Make sure that the channel is registered with {@link #RegisterChatChannel(Channel)}.<br>
|
|
||||||
* This will also send the error message to the sender, if they can't send the message.
|
|
||||||
*
|
|
||||||
* @param cm The message to send
|
|
||||||
* @return The event cancelled state
|
|
||||||
*/
|
|
||||||
public static boolean SendChatMessage(ChatMessage cm) {
|
|
||||||
return SendChatMessage(cm, cm.getUser().channel().get());
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Sends a chat message to Minecraft. Make sure that the channel is registered with {@link #RegisterChatChannel(Channel)}.<br>
|
|
||||||
* This will also send the error message to the sender, if they can't send the message.
|
|
||||||
*
|
|
||||||
* @param cm The message to send
|
|
||||||
* @param channel The MC channel to send in
|
|
||||||
* @return The event cancelled state
|
|
||||||
*/
|
|
||||||
public static boolean SendChatMessage(ChatMessage cm, Channel channel) {
|
|
||||||
if (!Channel.getChannelList().contains(channel))
|
|
||||||
throw new RuntimeException("Channel " + channel.DisplayName().get() + " not registered!");
|
|
||||||
if (!channel.Enabled().get()) {
|
|
||||||
cm.getSender().sendMessage("§cThe channel '" + channel.DisplayName().get() + "' is disabled!");
|
|
||||||
return true; //Cancel sending if channel is disabled
|
|
||||||
}
|
|
||||||
val permcheck = cm.getPermCheck();
|
|
||||||
RecipientTestResult rtr = getScoreOrSendError(channel, permcheck);
|
|
||||||
int score = rtr.score;
|
|
||||||
if (score == Channel.SCORE_SEND_NOPE || rtr.groupID == null)
|
|
||||||
return true;
|
|
||||||
TBMCChatPreprocessEvent eventPre = new TBMCChatPreprocessEvent(cm.getSender(), channel, cm.getMessage());
|
|
||||||
Bukkit.getPluginManager().callEvent(eventPre);
|
|
||||||
if (eventPre.isCancelled())
|
|
||||||
return true;
|
|
||||||
cm.setMessage(eventPre.getMessage());
|
|
||||||
TBMCChatEvent event;
|
|
||||||
event = new TBMCChatEvent(channel, cm, rtr);
|
|
||||||
Bukkit.getPluginManager().callEvent(event);
|
|
||||||
return event.isCancelled();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Sends a regular message to Minecraft. Make sure that the channel is registered with {@link #RegisterChatChannel(Channel)}.
|
|
||||||
*
|
|
||||||
* @param channel
|
|
||||||
* The channel to send to
|
|
||||||
* @param rtr
|
|
||||||
* The score&group to use to find the group - use {@link RecipientTestResult#ALL} if the channel doesn't have scores
|
|
||||||
* @param message
|
|
||||||
* The message to send
|
|
||||||
* @param exceptions Platforms where this message shouldn't be sent (same as {@link ChatMessage#getOrigin()}
|
|
||||||
* @return The event cancelled state
|
|
||||||
*/
|
|
||||||
public static boolean SendSystemMessage(Channel channel, RecipientTestResult rtr, String message, TBMCSystemChatEvent.BroadcastTarget target, String... exceptions) {
|
|
||||||
if (!Channel.getChannelList().contains(channel))
|
|
||||||
throw new RuntimeException("Channel " + channel.DisplayName().get() + " not registered!");
|
|
||||||
if (!channel.Enabled().get())
|
|
||||||
return true; //Cancel sending
|
|
||||||
if (!Arrays.asList(exceptions).contains("Minecraft"))
|
|
||||||
Bukkit.getConsoleSender().sendMessage("[" + channel.DisplayName().get() + "] " + message);
|
|
||||||
TBMCSystemChatEvent event = new TBMCSystemChatEvent(channel, message, rtr.score, rtr.groupID, exceptions, target);
|
|
||||||
Bukkit.getPluginManager().callEvent(event);
|
|
||||||
return event.isCancelled();
|
|
||||||
}
|
|
||||||
|
|
||||||
private static RecipientTestResult getScoreOrSendError(Channel channel, CommandSender sender) {
|
|
||||||
RecipientTestResult result = channel.getRTR(sender);
|
|
||||||
if (result.errormessage != null)
|
|
||||||
sender.sendMessage("§c" + result.errormessage);
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Register a chat channel. See {@link Channel#Channel(String, Color, String, java.util.function.Function)} for details.
|
|
||||||
*
|
|
||||||
* @param channel
|
|
||||||
* A new {@link Channel} to register
|
|
||||||
*/
|
|
||||||
public static void RegisterChatChannel(Channel channel) {
|
|
||||||
Channel.RegisterChannel(channel);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,111 +0,0 @@
|
||||||
package buttondevteam.lib.chat;
|
|
||||||
|
|
||||||
import buttondevteam.lib.architecture.Component;
|
|
||||||
import javassist.Modifier;
|
|
||||||
import lombok.Getter;
|
|
||||||
import org.bukkit.command.CommandSender;
|
|
||||||
import org.bukkit.plugin.Plugin;
|
|
||||||
|
|
||||||
import java.util.function.Function;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Extend this class to create new TBMCCommand and use {@link TBMCChatAPI#AddCommand(org.bukkit.plugin.java.JavaPlugin, TBMCCommandBase)} to add it. <u><b>Note:</b></u> The command path (command name
|
|
||||||
* and subcommand arguments) will be the class name by default, removing any "command" from it. To change it (especially for subcommands), use the path field in the {@link CommandClass} annotation.
|
|
||||||
*
|
|
||||||
* @author Norbi
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
@TBMCCommandEnforcer
|
|
||||||
public abstract class TBMCCommandBase {
|
|
||||||
|
|
||||||
public TBMCCommandBase() {
|
|
||||||
path = getcmdpath();
|
|
||||||
modonly = ismodonly();
|
|
||||||
}
|
|
||||||
|
|
||||||
public abstract boolean OnCommand(CommandSender sender, String alias, String[] args);
|
|
||||||
|
|
||||||
public abstract String[] GetHelpText(String alias);
|
|
||||||
|
|
||||||
private final String path;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The command's path, or name if top-level command.<br>
|
|
||||||
* For example:<br>
|
|
||||||
* "u admin updateplugin" or "u" for the top level one<br>
|
|
||||||
* <u>The path must be lowercase!</u><br>
|
|
||||||
* <b>Abstract classes with no {@link CommandClass} annotations will be ignored.</b>
|
|
||||||
*
|
|
||||||
* @return The command path, <i>which is the command class name by default</i> (removing any "command" from it) - Change via the {@link CommandClass} annotation
|
|
||||||
*/
|
|
||||||
public final String GetCommandPath() {
|
|
||||||
return path;
|
|
||||||
}
|
|
||||||
|
|
||||||
private String getcmdpath() {
|
|
||||||
if (!getClass().isAnnotationPresent(CommandClass.class))
|
|
||||||
throw new RuntimeException(
|
|
||||||
"No @CommandClass annotation on command class " + getClass().getSimpleName() + "!");
|
|
||||||
Function<Class<?>, String> getFromClass = cl -> cl.getSimpleName().toLowerCase().replace("commandbase", "") // <-- ...
|
|
||||||
.replace("command", "");
|
|
||||||
String path = getClass().getAnnotation(CommandClass.class).path(),
|
|
||||||
prevpath = path = path.length() == 0 ? getFromClass.apply(getClass()) : path;
|
|
||||||
for (Class<?> cl = getClass().getSuperclass(); cl != null
|
|
||||||
&& !cl.getPackage().getName().equals(TBMCCommandBase.class.getPackage().getName()); cl = cl
|
|
||||||
.getSuperclass()) { //
|
|
||||||
String newpath;
|
|
||||||
if (!cl.isAnnotationPresent(CommandClass.class)
|
|
||||||
|| (newpath = cl.getAnnotation(CommandClass.class).path()).length() == 0
|
|
||||||
|| newpath.equals(prevpath)) {
|
|
||||||
if ((Modifier.isAbstract(cl.getModifiers()) && !cl.isAnnotationPresent(CommandClass.class))
|
|
||||||
|| cl.getAnnotation(CommandClass.class).excludeFromPath()) // <--
|
|
||||||
continue;
|
|
||||||
newpath = getFromClass.apply(cl);
|
|
||||||
}
|
|
||||||
path = (prevpath = newpath) + " " + path;
|
|
||||||
}
|
|
||||||
return path;
|
|
||||||
}
|
|
||||||
|
|
||||||
Plugin plugin; // Used By TBMCChatAPI
|
|
||||||
|
|
||||||
public final Plugin getPlugin() { // Used by CommandCaller (ButtonChat)
|
|
||||||
return plugin;
|
|
||||||
}
|
|
||||||
|
|
||||||
public final boolean isPlayerOnly() {
|
|
||||||
return this instanceof PlayerCommandBase ||
|
|
||||||
(this instanceof OptionallyPlayerCommandBase &&
|
|
||||||
(!getClass().isAnnotationPresent(OptionallyPlayerCommandClass.class)
|
|
||||||
|| getClass().getAnnotation(OptionallyPlayerCommandClass.class).playerOnly()));
|
|
||||||
}
|
|
||||||
|
|
||||||
private final boolean modonly;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns true if this class' or any superclass' modOnly property is set to true.
|
|
||||||
*/
|
|
||||||
public final boolean isModOnly() {
|
|
||||||
return modonly;
|
|
||||||
}
|
|
||||||
|
|
||||||
private boolean ismodonly() {
|
|
||||||
if (!getClass().isAnnotationPresent(CommandClass.class))
|
|
||||||
throw new RuntimeException(
|
|
||||||
"No @CommandClass annotation on command class " + getClass().getSimpleName() + "!");
|
|
||||||
boolean modOnly = getClass().getAnnotation(CommandClass.class).modOnly();
|
|
||||||
for (Class<?> cl = getClass().getSuperclass(); cl != null
|
|
||||||
&& !cl.getPackage().getName().equals(TBMCCommandBase.class.getPackage().getName()); cl = cl
|
|
||||||
.getSuperclass()) { //
|
|
||||||
if (cl.isAnnotationPresent(CommandClass.class) && !modOnly
|
|
||||||
&& cl.getAnnotation(CommandClass.class).modOnly()) {
|
|
||||||
modOnly = true;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return modOnly;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Getter
|
|
||||||
Component component; //May be null
|
|
||||||
}
|
|
|
@ -1,14 +0,0 @@
|
||||||
package buttondevteam.lib.chat;
|
|
||||||
|
|
||||||
import java.lang.annotation.ElementType;
|
|
||||||
import java.lang.annotation.Inherited;
|
|
||||||
import java.lang.annotation.Retention;
|
|
||||||
import java.lang.annotation.RetentionPolicy;
|
|
||||||
import java.lang.annotation.Target;
|
|
||||||
|
|
||||||
@Retention(RetentionPolicy.CLASS)
|
|
||||||
@Target(ElementType.TYPE)
|
|
||||||
@Inherited
|
|
||||||
public @interface TBMCCommandEnforcer {
|
|
||||||
|
|
||||||
}
|
|
|
@ -1,25 +0,0 @@
|
||||||
package buttondevteam.lib.player;
|
|
||||||
|
|
||||||
import buttondevteam.core.component.channel.Channel;
|
|
||||||
import org.bukkit.configuration.file.YamlConfiguration;
|
|
||||||
|
|
||||||
public class ChannelPlayerData { //I just want this to work
|
|
||||||
private final PlayerData<String> data;
|
|
||||||
private final Channel def;
|
|
||||||
|
|
||||||
public ChannelPlayerData(String name, YamlConfiguration yaml, Channel def) {
|
|
||||||
data = new PlayerData<>(name, yaml, "");
|
|
||||||
this.def = def;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Channel get() {
|
|
||||||
String str = data.get();
|
|
||||||
if (str.isEmpty())
|
|
||||||
return def;
|
|
||||||
return Channel.getChannels().filter(c -> str.equals(c.ID)).findAny().orElse(def);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void set(Channel value) {
|
|
||||||
data.set(value.ID);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,329 +0,0 @@
|
||||||
package buttondevteam.lib.player;
|
|
||||||
|
|
||||||
import buttondevteam.core.component.channel.Channel;
|
|
||||||
import buttondevteam.lib.TBMCCoreAPI;
|
|
||||||
import com.google.common.collect.HashBiMap;
|
|
||||||
import lombok.val;
|
|
||||||
import org.bukkit.Bukkit;
|
|
||||||
import org.bukkit.command.CommandSender;
|
|
||||||
import org.bukkit.configuration.file.YamlConfiguration;
|
|
||||||
|
|
||||||
import javax.annotation.Nullable;
|
|
||||||
import java.io.File;
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.HashMap;
|
|
||||||
import java.util.Optional;
|
|
||||||
import java.util.function.Consumer;
|
|
||||||
import java.util.function.Function;
|
|
||||||
|
|
||||||
@ChromaGamerEnforcer
|
|
||||||
public abstract class ChromaGamerBase implements AutoCloseable {
|
|
||||||
public static final String TBMC_PLAYERS_DIR = "TBMC/players/";
|
|
||||||
|
|
||||||
private static final HashBiMap<Class<? extends ChromaGamerBase>, String> playerTypes = HashBiMap.create();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Used for connecting with every type of user ({@link #connectWith(ChromaGamerBase)})
|
|
||||||
*/
|
|
||||||
public static void RegisterPluginUserClass(Class<? extends ChromaGamerBase> userclass) {
|
|
||||||
if (userclass.isAnnotationPresent(UserClass.class))
|
|
||||||
playerTypes.put(userclass, userclass.getAnnotation(UserClass.class).foldername());
|
|
||||||
else if (userclass.isAnnotationPresent(AbstractUserClass.class))
|
|
||||||
playerTypes.put(userclass.getAnnotation(AbstractUserClass.class).prototype(),
|
|
||||||
userclass.getAnnotation(AbstractUserClass.class).foldername());
|
|
||||||
else // <-- Really important
|
|
||||||
throw new RuntimeException("Class not registered as a user class! Use @UserClass or TBMCPlayerBase");
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the folder name for the given player class.
|
|
||||||
*
|
|
||||||
* @param cl
|
|
||||||
* The class to get the folder from (like {@link TBMCPlayerBase} or one of it's subclasses)
|
|
||||||
* @return The folder name for the given type
|
|
||||||
* @throws RuntimeException
|
|
||||||
* If the class doesn't have the {@link UserClass} annotation.
|
|
||||||
*/
|
|
||||||
public static <T extends ChromaGamerBase> String getFolderForType(Class<T> cl) {
|
|
||||||
if (cl.isAnnotationPresent(UserClass.class))
|
|
||||||
return cl.getAnnotation(UserClass.class).foldername();
|
|
||||||
else if (cl.isAnnotationPresent(AbstractUserClass.class))
|
|
||||||
return cl.getAnnotation(AbstractUserClass.class).foldername();
|
|
||||||
throw new RuntimeException("Class not registered as a user class! Use @UserClass or @AbstractUserClass");
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the player class for the given folder name.
|
|
||||||
*
|
|
||||||
* @param foldername
|
|
||||||
* The folder to get the class from (like "minecraft")
|
|
||||||
* @return The type for the given folder name or null if not found
|
|
||||||
*/
|
|
||||||
public static Class<? extends ChromaGamerBase> getTypeForFolder(String foldername) {
|
|
||||||
return playerTypes.inverse().get(foldername);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This method returns the filename for this player data. For example, for Minecraft-related data, MC UUIDs, for Discord data, use Discord IDs, etc.<br>
|
|
||||||
* <b>Does not include .yml</b>
|
|
||||||
*/
|
|
||||||
public final String getFileName() {
|
|
||||||
return plugindata.getString(getFolder() + "_id");
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Use {@link #data(Object)} or {@link #data(String, Object)} where possible; the 'id' must be always set
|
|
||||||
*/
|
|
||||||
protected YamlConfiguration plugindata;
|
|
||||||
|
|
||||||
/***
|
|
||||||
* Loads a user from disk and returns the user object. Make sure to use the subclasses' methods, where possible, like {@link TBMCPlayerBase#getPlayer(java.util.UUID, Class)}
|
|
||||||
*
|
|
||||||
* @param fname Filename without .yml, usually UUID
|
|
||||||
* @param cl User class
|
|
||||||
* @return The user object
|
|
||||||
*/
|
|
||||||
public static <T extends ChromaGamerBase> T getUser(String fname, Class<T> cl) {
|
|
||||||
try {
|
|
||||||
T obj = cl.newInstance();
|
|
||||||
final String folder = getFolderForType(cl);
|
|
||||||
final File file = new File(TBMC_PLAYERS_DIR + folder, fname + ".yml");
|
|
||||||
file.getParentFile().mkdirs();
|
|
||||||
obj.plugindata = YamlConfiguration.loadConfiguration(file);
|
|
||||||
obj.plugindata.set(folder + "_id", fname);
|
|
||||||
return obj;
|
|
||||||
} catch (Exception e) {
|
|
||||||
TBMCCoreAPI.SendException("An error occured while loading a " + cl.getSimpleName() + "!", e);
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static ArrayList<Function<CommandSender, ? extends Optional<? extends ChromaGamerBase>>> senderConverters = new ArrayList<>();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Adds a converter to the start of the list.
|
|
||||||
*
|
|
||||||
* @param converter The converter that returns an object corresponding to the sender or null, if it's not the right type.
|
|
||||||
*/
|
|
||||||
public static <T extends ChromaGamerBase> void addConverter(Function<CommandSender, Optional<T>> converter) {
|
|
||||||
senderConverters.add(0, converter);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get from the given sender. the object's type will depend on the sender's type. May be null, but shouldn't be.
|
|
||||||
*
|
|
||||||
* @param sender The sender to use
|
|
||||||
* @return A user as returned by a converter or null if none can supply it
|
|
||||||
*/
|
|
||||||
public static ChromaGamerBase getFromSender(CommandSender sender) {
|
|
||||||
for (val converter : senderConverters) {
|
|
||||||
val ocg = converter.apply(sender);
|
|
||||||
if (ocg.isPresent())
|
|
||||||
return ocg.get();
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Saves the player. It'll pass all exceptions to the caller. To automatically handle the exception, use {@link #save()} instead.
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
public void close() throws Exception {
|
|
||||||
if (plugindata.getKeys(false).size() > 0)
|
|
||||||
plugindata.save(new File(TBMC_PLAYERS_DIR + getFolder(), getFileName() + ".yml"));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Saves the player. It'll handle all exceptions that may happen. To catch the exception, use {@link #close()} instead.
|
|
||||||
*/
|
|
||||||
public void save() {
|
|
||||||
try {
|
|
||||||
close();
|
|
||||||
} catch (Exception e) {
|
|
||||||
TBMCCoreAPI.SendException("Error while saving player to " + getFolder() + "/" + getFileName() + ".yml!", e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Connect two accounts. Do not use for connecting two Minecraft accounts or similar. Also make sure you have the "id" tag set
|
|
||||||
*
|
|
||||||
* @param user
|
|
||||||
* The account to connect with
|
|
||||||
*/
|
|
||||||
public <T extends ChromaGamerBase> void connectWith(T user) {
|
|
||||||
// Set the ID, go through all linked files and connect them as well
|
|
||||||
if (!playerTypes.containsKey(getClass()))
|
|
||||||
throw new RuntimeException("Class not registered as a user class! Use TBMCCoreAPI.RegisterUserClass");
|
|
||||||
final String ownFolder = getFolder();
|
|
||||||
final String userFolder = user.getFolder();
|
|
||||||
if (ownFolder.equalsIgnoreCase(userFolder))
|
|
||||||
throw new RuntimeException("Do not connect two accounts of the same type! Type: "+ownFolder);
|
|
||||||
user.plugindata.set(ownFolder + "_id", plugindata.getString(ownFolder + "_id"));
|
|
||||||
plugindata.set(userFolder + "_id", user.plugindata.getString(userFolder + "_id"));
|
|
||||||
Consumer<YamlConfiguration> sync = sourcedata -> {
|
|
||||||
final String sourcefolder = sourcedata == plugindata ? ownFolder : userFolder;
|
|
||||||
final String id = sourcedata.getString(sourcefolder + "_id");
|
|
||||||
for (val entry : playerTypes.entrySet()) { // Set our ID in all files we can find, both from our connections and the new ones
|
|
||||||
if (entry.getKey() == getClass() || entry.getKey() == user.getClass())
|
|
||||||
continue;
|
|
||||||
final String otherid = sourcedata.getString(entry.getValue() + "_id");
|
|
||||||
if (otherid == null)
|
|
||||||
continue;
|
|
||||||
try (ChromaGamerBase cg = getUser(otherid, entry.getKey())) {
|
|
||||||
cg.plugindata.set(sourcefolder + "_id", id); // Set new IDs
|
|
||||||
for (val item : playerTypes.entrySet())
|
|
||||||
if (sourcedata.contains(item.getValue() + "_id"))
|
|
||||||
cg.plugindata.set(item.getValue() + "_id", sourcedata.getString(item.getValue() + "_id")); // Set all existing IDs
|
|
||||||
} catch (Exception e) {
|
|
||||||
TBMCCoreAPI.SendException("Failed to update " + sourcefolder + " ID in player files for " + id
|
|
||||||
+ " in folder with " + entry.getValue() + " id " + otherid + "!", e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
sync.accept(plugindata);
|
|
||||||
sync.accept(user.plugindata);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Retunrs the ID for the T typed player object connected with this one or null if no connection found.
|
|
||||||
*
|
|
||||||
* @param cl
|
|
||||||
* The player class to get the ID from
|
|
||||||
* @return The ID or null if not found
|
|
||||||
*/
|
|
||||||
public <T extends ChromaGamerBase> String getConnectedID(Class<T> cl) {
|
|
||||||
return plugindata.getString(getFolderForType(cl) + "_id");
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns this player as a plugin player. This will return a new instance unless the player is online.<br>
|
|
||||||
* Make sure to close both the returned and this object. A try-with-resources block or two can help.<br>
|
|
||||||
*
|
|
||||||
* @param cl
|
|
||||||
* The target player class
|
|
||||||
* @return The player as a {@link T} object or null if not having an account there
|
|
||||||
*/
|
|
||||||
@SuppressWarnings("unchecked")
|
|
||||||
@Nullable
|
|
||||||
public <T extends ChromaGamerBase> T getAs(Class<T> cl) { // TODO: Provide a way to use TBMCPlayerBase's loaded players
|
|
||||||
if (cl.getSimpleName().equals(getClass().getSimpleName()))
|
|
||||||
return (T) this;
|
|
||||||
String newfolder = getFolderForType(cl);
|
|
||||||
if (newfolder == null)
|
|
||||||
throw new RuntimeException("The specified class " + cl.getSimpleName() + " isn't registered!");
|
|
||||||
if (newfolder.equals(getFolder())) // If in the same folder, the same filename is used
|
|
||||||
return getUser(getFileName(), cl);
|
|
||||||
if (!plugindata.contains(newfolder + "_id"))
|
|
||||||
return null;
|
|
||||||
return getUser(plugindata.getString(newfolder + "_id"), cl);
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getFolder() {
|
|
||||||
return getFolderForType(getClass());
|
|
||||||
}
|
|
||||||
|
|
||||||
private void ThrowIfNoUser() {
|
|
||||||
if (!getClass().isAnnotationPresent(UserClass.class)
|
|
||||||
&& !getClass().isAnnotationPresent(AbstractUserClass.class))
|
|
||||||
throw new RuntimeException("Class not registered as a user class! Use @UserClass");
|
|
||||||
}
|
|
||||||
|
|
||||||
@SuppressWarnings("rawtypes")
|
|
||||||
private final HashMap<String, PlayerData> datamap = new HashMap<>();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Use from a data() method, which is in a method with the name of the key. For example, use flair() for the enclosing method of the outer data() to save to and load from "flair"
|
|
||||||
*
|
|
||||||
* @return A data object with methods to get and set
|
|
||||||
*/
|
|
||||||
@SuppressWarnings("unchecked")
|
|
||||||
protected <T> PlayerData<T> data(String sectionname, T def) {
|
|
||||||
ThrowIfNoUser();
|
|
||||||
String mname = sectionname + "." + new Exception().getStackTrace()[2].getMethodName();
|
|
||||||
if (!datamap.containsKey(mname))
|
|
||||||
datamap.put(mname, new PlayerData<T>(mname, plugindata, def));
|
|
||||||
return datamap.get(mname);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Use from a method with the name of the key. For example, use flair() for the enclosing method to save to and load from "flair"
|
|
||||||
*
|
|
||||||
* @return A data object with methods to get and set
|
|
||||||
*/
|
|
||||||
@SuppressWarnings("unchecked")
|
|
||||||
protected <T> PlayerData<T> data(T def) {
|
|
||||||
ThrowIfNoUser();
|
|
||||||
String mname = new Exception().getStackTrace()[1].getMethodName();
|
|
||||||
if (!datamap.containsKey(mname))
|
|
||||||
datamap.put(mname, new PlayerData<T>(mname, plugindata, def));
|
|
||||||
return datamap.get(mname);
|
|
||||||
}
|
|
||||||
|
|
||||||
@SuppressWarnings("rawtypes")
|
|
||||||
private final HashMap<String, EnumPlayerData> dataenummap = new HashMap<>();
|
|
||||||
private ChannelPlayerData datachannel;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Use from a data() method, which is in a method with the name of the key. For example, use flair() for the enclosing method of the outer data() to save to and load from "flair"
|
|
||||||
*
|
|
||||||
* @return A data object with methods to get and set
|
|
||||||
*/
|
|
||||||
@SuppressWarnings("unchecked")
|
|
||||||
protected <T extends Enum<T>> EnumPlayerData<T> dataEnum(String sectionname, Class<T> cl, T def) {
|
|
||||||
ThrowIfNoUser();
|
|
||||||
String mname = sectionname + "." + new Exception().getStackTrace()[2].getMethodName();
|
|
||||||
if (!dataenummap.containsKey(mname))
|
|
||||||
dataenummap.put(mname, new EnumPlayerData<T>(mname, plugindata, cl, def));
|
|
||||||
return dataenummap.get(mname);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Use from a method with the name of the key. For example, use flair() for the enclosing method to save to and load from "flair"
|
|
||||||
*
|
|
||||||
* @return A data object with methods to get and set
|
|
||||||
*/
|
|
||||||
@SuppressWarnings("unchecked")
|
|
||||||
protected <T extends Enum<T>> EnumPlayerData<T> dataEnum(Class<T> cl, T def) {
|
|
||||||
ThrowIfNoUser();
|
|
||||||
String mname = new Exception().getStackTrace()[1].getMethodName();
|
|
||||||
if (!dataenummap.containsKey(mname))
|
|
||||||
dataenummap.put(mname, new EnumPlayerData<T>(mname, plugindata, cl, def));
|
|
||||||
return dataenummap.get(mname);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Channel
|
|
||||||
*
|
|
||||||
* @return A data object with methods to get and set
|
|
||||||
*/
|
|
||||||
@SuppressWarnings("unchecked")
|
|
||||||
protected ChannelPlayerData dataChannel(Channel def) { //TODO: Make interface with fromString() method and require use of that for player data types
|
|
||||||
ThrowIfNoUser();
|
|
||||||
if (datachannel == null)
|
|
||||||
datachannel = new ChannelPlayerData("channel", plugindata, def);
|
|
||||||
return datachannel;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get player information. This method calls the {@link TBMCPlayerGetInfoEvent} to get all the player information across the TBMC plugins.
|
|
||||||
*
|
|
||||||
* @param target
|
|
||||||
* The {@link InfoTarget} to return the info for.
|
|
||||||
* @return The player information.
|
|
||||||
*/
|
|
||||||
public String getInfo(InfoTarget target) {
|
|
||||||
TBMCPlayerGetInfoEvent event = new TBMCPlayerGetInfoEvent(this, target);
|
|
||||||
Bukkit.getServer().getPluginManager().callEvent(event);
|
|
||||||
return event.getResult();
|
|
||||||
}
|
|
||||||
|
|
||||||
public enum InfoTarget {
|
|
||||||
MCHover, MCCommand, Discord
|
|
||||||
}
|
|
||||||
|
|
||||||
//-----------------------------------------------------------------
|
|
||||||
|
|
||||||
public ChannelPlayerData channel() {
|
|
||||||
return dataChannel(Channel.GlobalChat);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,26 +0,0 @@
|
||||||
package buttondevteam.lib.player;
|
|
||||||
|
|
||||||
import org.bukkit.configuration.file.YamlConfiguration;
|
|
||||||
|
|
||||||
public class EnumPlayerData<T extends Enum<T>> {
|
|
||||||
private final PlayerData<String> data;
|
|
||||||
private final Class<T> cl;
|
|
||||||
private final T def;
|
|
||||||
|
|
||||||
public EnumPlayerData(String name, YamlConfiguration yaml, Class<T> cl, T def) {
|
|
||||||
data = new PlayerData<String>(name, yaml, "");
|
|
||||||
this.cl = cl;
|
|
||||||
this.def = def;
|
|
||||||
}
|
|
||||||
|
|
||||||
public T get() {
|
|
||||||
String str = data.get();
|
|
||||||
if (str.isEmpty())
|
|
||||||
return def;
|
|
||||||
return Enum.valueOf(cl, str);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void set(T value) {
|
|
||||||
data.set(value.toString());
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,37 +0,0 @@
|
||||||
package buttondevteam.lib.player;
|
|
||||||
|
|
||||||
import org.bukkit.configuration.file.YamlConfiguration;
|
|
||||||
|
|
||||||
public class PlayerData<T> {
|
|
||||||
private final String name;
|
|
||||||
private final YamlConfiguration yaml;
|
|
||||||
private final T def;
|
|
||||||
|
|
||||||
public PlayerData(String name, YamlConfiguration yaml, T def) {
|
|
||||||
this.name = name;
|
|
||||||
this.yaml = yaml;
|
|
||||||
this.def = def;
|
|
||||||
}
|
|
||||||
|
|
||||||
@SuppressWarnings("unchecked")
|
|
||||||
// @Deprecated - What was once enforced (2 days ago from now) vanished now
|
|
||||||
public T get() {
|
|
||||||
Object value = yaml.get(name, def);
|
|
||||||
if (value instanceof Integer) {
|
|
||||||
if (def instanceof Short) // If the default is Short the value must be as well because both are T
|
|
||||||
return (T) (Short) ((Integer) value).shortValue();
|
|
||||||
if (def instanceof Long)
|
|
||||||
return (T) (Long) ((Integer) value).longValue();
|
|
||||||
}
|
|
||||||
return (T) value;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void set(T value) {
|
|
||||||
yaml.set(name, value);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String toString() {
|
|
||||||
return get().toString();
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,190 +0,0 @@
|
||||||
package buttondevteam.lib.player;
|
|
||||||
|
|
||||||
import buttondevteam.core.component.towny.TownyComponent;
|
|
||||||
import buttondevteam.lib.TBMCCoreAPI;
|
|
||||||
import org.bukkit.Bukkit;
|
|
||||||
import org.bukkit.OfflinePlayer;
|
|
||||||
import org.bukkit.entity.Player;
|
|
||||||
|
|
||||||
import java.util.Set;
|
|
||||||
import java.util.UUID;
|
|
||||||
import java.util.concurrent.ConcurrentHashMap;
|
|
||||||
|
|
||||||
@AbstractUserClass(foldername = "minecraft", prototype = TBMCPlayer.class)
|
|
||||||
@TBMCPlayerEnforcer
|
|
||||||
public abstract class TBMCPlayerBase extends ChromaGamerBase {
|
|
||||||
protected UUID uuid;
|
|
||||||
|
|
||||||
private String pluginname;
|
|
||||||
|
|
||||||
protected TBMCPlayerBase() {
|
|
||||||
if (getClass().isAnnotationPresent(PlayerClass.class))
|
|
||||||
pluginname = getClass().getAnnotation(PlayerClass.class).pluginname();
|
|
||||||
else
|
|
||||||
throw new RuntimeException("Class not defined as player class! Use @PlayerClass");
|
|
||||||
}
|
|
||||||
|
|
||||||
public UUID getUUID() {
|
|
||||||
if (uuid == null)
|
|
||||||
uuid = UUID.fromString(getFileName());
|
|
||||||
return uuid;
|
|
||||||
}
|
|
||||||
|
|
||||||
public PlayerData<String> PlayerName() {
|
|
||||||
return super.data(null);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Use from a method with the name of the key. For example, use flair() for the enclosing method to save to and load from "flair"
|
|
||||||
*
|
|
||||||
* @return A data object with methods to get and set
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
protected <T> PlayerData<T> data(T def) {
|
|
||||||
return super.data(pluginname, def);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Use from a method with the name of the key. For example, use flair() for the enclosing method to save to and load from "flair"
|
|
||||||
*
|
|
||||||
* @return A data object with methods to get and set
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
protected <T extends Enum<T>> EnumPlayerData<T> dataEnum(Class<T> cl, T def) {
|
|
||||||
return super.dataEnum(pluginname, cl, def);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get player as a plugin player
|
|
||||||
*
|
|
||||||
* @param uuid
|
|
||||||
* The UUID of the player to get
|
|
||||||
* @param cl
|
|
||||||
* The type of the player
|
|
||||||
* @return The requested player object
|
|
||||||
*/
|
|
||||||
@SuppressWarnings("unchecked")
|
|
||||||
public static <T extends TBMCPlayerBase> T getPlayer(UUID uuid, Class<T> cl) {
|
|
||||||
if (playermap.containsKey(uuid + "-" + cl.getSimpleName()))
|
|
||||||
return (T) playermap.get(uuid + "-" + cl.getSimpleName());
|
|
||||||
try {
|
|
||||||
T player;
|
|
||||||
if (playermap.containsKey(uuid + "-" + TBMCPlayer.class.getSimpleName())) {
|
|
||||||
player = cl.newInstance();
|
|
||||||
player.plugindata = playermap.get(uuid + "-" + TBMCPlayer.class.getSimpleName()).plugindata;
|
|
||||||
playermap.put(uuid + "-" + cl.getSimpleName(), player); // It will get removed on player quit
|
|
||||||
} else
|
|
||||||
player = ChromaGamerBase.getUser(uuid.toString(), cl);
|
|
||||||
player.uuid = uuid;
|
|
||||||
return player;
|
|
||||||
} catch (Exception e) {
|
|
||||||
TBMCCoreAPI.SendException(
|
|
||||||
"Failed to get player with UUID " + uuid + " and class " + cl.getSimpleName() + "!", e);
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Key: UUID-Class
|
|
||||||
*/
|
|
||||||
static final ConcurrentHashMap<String, TBMCPlayerBase> playermap = new ConcurrentHashMap<>();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Gets the TBMCPlayer object as a specific plugin player, keeping it's data<br>
|
|
||||||
* Make sure to use try-with-resources with this to save the data, as it may need to load the file
|
|
||||||
*
|
|
||||||
* @param cl
|
|
||||||
* The TBMCPlayer subclass
|
|
||||||
*/
|
|
||||||
public <T extends TBMCPlayerBase> T asPluginPlayer(Class<T> cl) {
|
|
||||||
return getPlayer(uuid, cl);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Only intended to use from ButtonCore
|
|
||||||
*/
|
|
||||||
public static void savePlayer(TBMCPlayerBase player) {
|
|
||||||
Bukkit.getServer().getPluginManager().callEvent(new TBMCPlayerSaveEvent(player));
|
|
||||||
try {
|
|
||||||
player.close();
|
|
||||||
} catch (Exception e) {
|
|
||||||
new Exception("Failed to save player data for " + player.PlayerName().get(), e).printStackTrace();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Only intended to use from ButtonCore
|
|
||||||
*/
|
|
||||||
public static void joinPlayer(Player p) {
|
|
||||||
TBMCPlayer player = TBMCPlayerBase.getPlayer(p.getUniqueId(), TBMCPlayer.class);
|
|
||||||
Bukkit.getLogger().info("Loaded player: " + player.PlayerName().get());
|
|
||||||
if (player.PlayerName().get() == null) {
|
|
||||||
player.PlayerName().set(p.getName());
|
|
||||||
Bukkit.getLogger().info("Player name saved: " + player.PlayerName().get());
|
|
||||||
} else if (!p.getName().equals(player.PlayerName().get())) {
|
|
||||||
Bukkit.getLogger().info("Renaming " + player.PlayerName().get() + " to " + p.getName());
|
|
||||||
TownyComponent.renameInTowny(player.PlayerName().get(), p.getName());
|
|
||||||
player.PlayerName().set(p.getName());
|
|
||||||
Bukkit.getLogger().info("Renaming done.");
|
|
||||||
}
|
|
||||||
playermap.put(p.getUniqueId() + "-" + TBMCPlayer.class.getSimpleName(), player);
|
|
||||||
|
|
||||||
// Load in other plugins
|
|
||||||
Bukkit.getServer().getPluginManager().callEvent(new TBMCPlayerLoadEvent(player));
|
|
||||||
Bukkit.getServer().getPluginManager().callEvent(new TBMCPlayerJoinEvent(player, p));
|
|
||||||
player.save();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Only intended to use from ButtonCore
|
|
||||||
*/
|
|
||||||
public static void quitPlayer(Player p) {
|
|
||||||
final TBMCPlayerBase player = playermap.get(p.getUniqueId() + "-" + TBMCPlayer.class.getSimpleName());
|
|
||||||
player.save();
|
|
||||||
Bukkit.getServer().getPluginManager().callEvent(new TBMCPlayerQuitEvent(player, p));
|
|
||||||
playermap.entrySet().removeIf(entry -> entry.getKey().startsWith(p.getUniqueId().toString()));
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void savePlayers() {
|
|
||||||
playermap.values().forEach(p -> {
|
|
||||||
try {
|
|
||||||
p.close();
|
|
||||||
} catch (Exception e) {
|
|
||||||
TBMCCoreAPI.SendException("Error while saving player " + p.PlayerName().get() + " (" + p.getFolder()
|
|
||||||
+ "/" + p.getFileName() + ")!", e);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This method returns a TBMC player from their name. Calling this method may return an offline player which will load it, therefore it's highly recommended to use {@link #close()} to unload the
|
|
||||||
* player data. Using try-with-resources may be the easiest way to achieve this. Example:
|
|
||||||
*
|
|
||||||
* <pre>
|
|
||||||
* {@code
|
|
||||||
* try(TBMCPlayer player = getFromName(p))
|
|
||||||
* {
|
|
||||||
* ...
|
|
||||||
* }
|
|
||||||
* </pre>
|
|
||||||
*
|
|
||||||
* @param name
|
|
||||||
* The player's name
|
|
||||||
* @return The {@link TBMCPlayer} object for the player
|
|
||||||
*/
|
|
||||||
public static <T extends TBMCPlayerBase> T getFromName(String name, Class<T> cl) {
|
|
||||||
@SuppressWarnings("deprecation")
|
|
||||||
OfflinePlayer p = Bukkit.getOfflinePlayer(name);
|
|
||||||
if (p != null)
|
|
||||||
return getPlayer(p.getUniqueId(), cl);
|
|
||||||
else
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void close() throws Exception {
|
|
||||||
Set<String> keys = plugindata.getKeys(false);
|
|
||||||
if (keys.size() > 1) // PlayerName is always saved, but we don't need a file for just that
|
|
||||||
super.close();
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,34 +0,0 @@
|
||||||
package buttondevteam.lib.player;
|
|
||||||
|
|
||||||
import org.bukkit.entity.Player;
|
|
||||||
import org.bukkit.event.Event;
|
|
||||||
import org.bukkit.event.HandlerList;
|
|
||||||
|
|
||||||
public class TBMCPlayerJoinEvent extends Event {
|
|
||||||
private static final HandlerList handlers = new HandlerList();
|
|
||||||
|
|
||||||
private final TBMCPlayerBase player;
|
|
||||||
private final Player player_;
|
|
||||||
|
|
||||||
public TBMCPlayerJoinEvent(TBMCPlayerBase player, Player player_) {
|
|
||||||
this.player = player;
|
|
||||||
this.player_ = player_;
|
|
||||||
}
|
|
||||||
|
|
||||||
public TBMCPlayerBase GetPlayer() {
|
|
||||||
return player;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Player getPlayer() { // :P
|
|
||||||
return player_;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public HandlerList getHandlers() {
|
|
||||||
return handlers;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static HandlerList getHandlerList() {
|
|
||||||
return handlers;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,27 +0,0 @@
|
||||||
package buttondevteam.lib.player;
|
|
||||||
|
|
||||||
import org.bukkit.event.Event;
|
|
||||||
import org.bukkit.event.HandlerList;
|
|
||||||
|
|
||||||
public class TBMCPlayerLoadEvent extends Event {
|
|
||||||
private static final HandlerList handlers = new HandlerList();
|
|
||||||
|
|
||||||
private final TBMCPlayerBase player;
|
|
||||||
|
|
||||||
public TBMCPlayerLoadEvent(TBMCPlayerBase player) {
|
|
||||||
this.player = player;
|
|
||||||
}
|
|
||||||
|
|
||||||
public TBMCPlayerBase GetPlayer() {
|
|
||||||
return player;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public HandlerList getHandlers() {
|
|
||||||
return handlers;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static HandlerList getHandlerList() {
|
|
||||||
return handlers;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,34 +0,0 @@
|
||||||
package buttondevteam.lib.player;
|
|
||||||
|
|
||||||
import org.bukkit.entity.Player;
|
|
||||||
import org.bukkit.event.Event;
|
|
||||||
import org.bukkit.event.HandlerList;
|
|
||||||
|
|
||||||
public class TBMCPlayerQuitEvent extends Event {
|
|
||||||
private static final HandlerList handlers = new HandlerList();
|
|
||||||
|
|
||||||
private final TBMCPlayerBase player;
|
|
||||||
private final Player player_;
|
|
||||||
|
|
||||||
public TBMCPlayerQuitEvent(TBMCPlayerBase player, Player player_) {
|
|
||||||
this.player = player;
|
|
||||||
this.player_ = player_;
|
|
||||||
}
|
|
||||||
|
|
||||||
public TBMCPlayerBase GetPlayer() {
|
|
||||||
return player;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Player getPlayer() {
|
|
||||||
return player_;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public HandlerList getHandlers() {
|
|
||||||
return handlers;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static HandlerList getHandlerList() {
|
|
||||||
return handlers;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,27 +0,0 @@
|
||||||
package buttondevteam.lib.player;
|
|
||||||
|
|
||||||
import org.bukkit.event.Event;
|
|
||||||
import org.bukkit.event.HandlerList;
|
|
||||||
|
|
||||||
public class TBMCPlayerSaveEvent extends Event {
|
|
||||||
private static final HandlerList handlers = new HandlerList();
|
|
||||||
|
|
||||||
private final TBMCPlayerBase player;
|
|
||||||
|
|
||||||
public TBMCPlayerSaveEvent(TBMCPlayerBase player) {
|
|
||||||
this.player = player;
|
|
||||||
}
|
|
||||||
|
|
||||||
public TBMCPlayerBase GetPlayer() {
|
|
||||||
return player;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public HandlerList getHandlers() {
|
|
||||||
return handlers;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static HandlerList getHandlerList() {
|
|
||||||
return handlers;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,54 +0,0 @@
|
||||||
package buttondevteam.core;
|
|
||||||
|
|
||||||
import buttondevteam.core.TestPlayerClass.TestEnum;
|
|
||||||
import buttondevteam.lib.player.ChromaGamerBase;
|
|
||||||
import buttondevteam.lib.player.TBMCPlayerBase;
|
|
||||||
import junit.framework.Test;
|
|
||||||
import junit.framework.TestCase;
|
|
||||||
import junit.framework.TestSuite;
|
|
||||||
import org.apache.commons.io.FileUtils;
|
|
||||||
|
|
||||||
import java.io.File;
|
|
||||||
import java.util.UUID;
|
|
||||||
|
|
||||||
public class PlayerDataTest extends TestCase {
|
|
||||||
public PlayerDataTest() {
|
|
||||||
super("Player data test");
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @return the suite of tests being tested
|
|
||||||
*/
|
|
||||||
public static Test suite() {
|
|
||||||
return new TestSuite(PlayerDataTest.class);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void testConfig() throws Exception {
|
|
||||||
TestPrepare.PrepareServer();
|
|
||||||
FileUtils.deleteDirectory(new File(ChromaGamerBase.TBMC_PLAYERS_DIR));
|
|
||||||
UUID uuid = new UUID(0L, 0L);
|
|
||||||
try (TestPlayerClass p = TBMCPlayerBase.getPlayer(uuid, TestPlayerClass.class)) {
|
|
||||||
p.PlayerName().set("Test");
|
|
||||||
assertEquals("Test", p.PlayerName().get());
|
|
||||||
assertEquals(TestEnum.A, p.testenum().get());
|
|
||||||
assertEquals((short) 0, (short) p.TestShort().get());
|
|
||||||
assertFalse(p.TestBool().get());
|
|
||||||
p.testenum().set(TestEnum.B);
|
|
||||||
assertEquals(TestEnum.B, p.testenum().get());
|
|
||||||
p.TestShort().set((short) 5);
|
|
||||||
assertEquals((short) 5, (short) p.TestShort().get());
|
|
||||||
p.TestBool().set(true);
|
|
||||||
assertTrue(p.TestBool().get());
|
|
||||||
} catch (Exception e) {
|
|
||||||
throw e;
|
|
||||||
}
|
|
||||||
try (TestPlayerClass p = TBMCPlayerBase.getPlayer(uuid, TestPlayerClass.class)) {
|
|
||||||
assertEquals("Test", p.PlayerName().get());
|
|
||||||
assertEquals(TestEnum.B, p.testenum().get());
|
|
||||||
assertEquals((short) 5, (short) p.TestShort().get());
|
|
||||||
assertTrue(p.TestBool().get());
|
|
||||||
} catch (Exception e) {
|
|
||||||
throw e;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,25 +0,0 @@
|
||||||
package buttondevteam.core;
|
|
||||||
|
|
||||||
import buttondevteam.lib.player.EnumPlayerData;
|
|
||||||
import buttondevteam.lib.player.PlayerClass;
|
|
||||||
import buttondevteam.lib.player.PlayerData;
|
|
||||||
import buttondevteam.lib.player.TBMCPlayerBase;
|
|
||||||
|
|
||||||
@PlayerClass(pluginname = "TestPlugin")
|
|
||||||
public class TestPlayerClass extends TBMCPlayerBase {
|
|
||||||
public EnumPlayerData<TestEnum> testenum() {
|
|
||||||
return dataEnum(TestEnum.class, TestEnum.A);
|
|
||||||
}
|
|
||||||
|
|
||||||
public enum TestEnum {
|
|
||||||
A, B
|
|
||||||
}
|
|
||||||
|
|
||||||
public PlayerData<Short> TestShort() {
|
|
||||||
return data((short) 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
public PlayerData<Boolean> TestBool() {
|
|
||||||
return data(false);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,24 +0,0 @@
|
||||||
<?xml version="1.0" encoding="UTF-8"?>
|
|
||||||
<module org.jetbrains.idea.maven.project.MavenProjectsManager.isMavenModule="true" type="JAVA_MODULE" version="4">
|
|
||||||
<component name="ExternalSystem" externalSystem="Maven" />
|
|
||||||
<component name="NewModuleRootManager" LANGUAGE_LEVEL="JDK_1_8">
|
|
||||||
<output url="file://$MODULE_DIR$/target/classes" />
|
|
||||||
<output-test url="file://$MODULE_DIR$/target/test-classes" />
|
|
||||||
<content url="file://$MODULE_DIR$">
|
|
||||||
<sourceFolder url="file://$MODULE_DIR$/src/main/java" isTestSource="false" />
|
|
||||||
<sourceFolder url="file://$MODULE_DIR$/src/main/resources" type="java-resource" />
|
|
||||||
<sourceFolder url="file://$MODULE_DIR$/src/test/java" isTestSource="true" />
|
|
||||||
<excludeFolder url="file://$MODULE_DIR$/target" />
|
|
||||||
</content>
|
|
||||||
<orderEntry type="inheritedJdk" />
|
|
||||||
<orderEntry type="sourceFolder" forTests="false" />
|
|
||||||
<orderEntry type="library" name="Maven: org.yaml:snakeyaml:1.21" level="project" />
|
|
||||||
<orderEntry type="library" name="Maven: org.spigotmc:spigot-api:1.12.2-R0.1-SNAPSHOT" level="project" />
|
|
||||||
<orderEntry type="library" name="Maven: commons-lang:commons-lang:2.6" level="project" />
|
|
||||||
<orderEntry type="library" name="Maven: com.googlecode.json-simple:json-simple:1.1.1" level="project" />
|
|
||||||
<orderEntry type="library" name="Maven: com.google.guava:guava:21.0" level="project" />
|
|
||||||
<orderEntry type="library" name="Maven: com.google.code.gson:gson:2.8.0" level="project" />
|
|
||||||
<orderEntry type="library" name="Maven: net.md-5:bungeecord-chat:1.12-SNAPSHOT" level="project" />
|
|
||||||
<orderEntry type="library" scope="TEST" name="Maven: junit:junit:3.8.1" level="project" />
|
|
||||||
</component>
|
|
||||||
</module>
|
|
43
ButtonProcessor/pom.xml
Executable file → Normal file
43
ButtonProcessor/pom.xml
Executable file → Normal file
|
@ -1,6 +1,6 @@
|
||||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||||
<modelVersion>4.0.0</modelVersion>
|
<modelVersion>4.0.0</modelVersion>
|
||||||
<repositories>
|
<repositories>
|
||||||
<repository>
|
<repository>
|
||||||
<id>spigot-repo</id>
|
<id>spigot-repo</id>
|
||||||
|
@ -11,7 +11,7 @@
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.yaml</groupId>
|
<groupId>org.yaml</groupId>
|
||||||
<artifactId>snakeyaml</artifactId>
|
<artifactId>snakeyaml</artifactId>
|
||||||
<version>1.21</version>
|
<version>1.32</version>
|
||||||
<scope>compile</scope>
|
<scope>compile</scope>
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
|
@ -21,13 +21,10 @@
|
||||||
<scope>compile</scope>
|
<scope>compile</scope>
|
||||||
</dependency>
|
</dependency>
|
||||||
</dependencies>
|
</dependencies>
|
||||||
<parent>
|
<!-- Can't use Core POM because it uses this processor -->
|
||||||
<groupId>com.github.TBMCPlugins</groupId>
|
<groupId>com.github.TBMCPlugins.ChromaCore</groupId>
|
||||||
<artifactId>ButtonCore</artifactId>
|
|
||||||
<version>master-SNAPSHOT</version>
|
|
||||||
</parent>
|
|
||||||
<groupId>com.github.TBMCPlugins.ButtonCore</groupId>
|
|
||||||
<artifactId>ButtonProcessor</artifactId>
|
<artifactId>ButtonProcessor</artifactId>
|
||||||
|
<version>master-SNAPSHOT</version>
|
||||||
<packaging>jar</packaging>
|
<packaging>jar</packaging>
|
||||||
|
|
||||||
<name>ButtonProcessor</name>
|
<name>ButtonProcessor</name>
|
||||||
|
@ -35,24 +32,26 @@
|
||||||
|
|
||||||
<build>
|
<build>
|
||||||
<plugins>
|
<plugins>
|
||||||
<plugin>
|
|
||||||
<artifactId>maven-compiler-plugin</artifactId>
|
|
||||||
<configuration>
|
|
||||||
<source>1.8</source>
|
|
||||||
<target>1.8</target>
|
|
||||||
<compilerArgument>-proc:none</compilerArgument>
|
|
||||||
</configuration>
|
|
||||||
</plugin>
|
|
||||||
<plugin>
|
<plugin>
|
||||||
<groupId>org.apache.maven.plugins</groupId>
|
<groupId>org.apache.maven.plugins</groupId>
|
||||||
<artifactId>maven-surefire-plugin</artifactId>
|
<artifactId>maven-compiler-plugin</artifactId>
|
||||||
<version>3.0.0-M3</version>
|
<version>3.8.0</version>
|
||||||
<configuration>
|
<configuration>
|
||||||
<useSystemClassLoader>false
|
<compilerArgument>-proc:none</compilerArgument>
|
||||||
</useSystemClassLoader> <!-- https://stackoverflow.com/a/53012553/2703239 -->
|
<source>8</source>
|
||||||
|
<target>8</target>
|
||||||
</configuration>
|
</configuration>
|
||||||
</plugin>
|
</plugin>
|
||||||
</plugins>
|
<plugin>
|
||||||
|
<groupId>org.apache.maven.plugins</groupId>
|
||||||
|
<artifactId>maven-surefire-plugin</artifactId>
|
||||||
|
<version>3.0.0-M3</version>
|
||||||
|
<configuration>
|
||||||
|
<useSystemClassLoader>false
|
||||||
|
</useSystemClassLoader> <!-- https://stackoverflow.com/a/53012553/2703239 -->
|
||||||
|
</configuration>
|
||||||
|
</plugin>
|
||||||
|
</plugins>
|
||||||
</build>
|
</build>
|
||||||
|
|
||||||
<properties>
|
<properties>
|
||||||
|
|
|
@ -21,35 +21,29 @@ import java.util.stream.Collectors;
|
||||||
@SupportedAnnotationTypes("buttondevteam.*")
|
@SupportedAnnotationTypes("buttondevteam.*")
|
||||||
public class ButtonProcessor extends AbstractProcessor {
|
public class ButtonProcessor extends AbstractProcessor {
|
||||||
@Override
|
@Override
|
||||||
public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) {
|
public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) {
|
||||||
if (configProcessor == null)
|
if (configProcessor == null)
|
||||||
configProcessor = new ConfigProcessor(processingEnv);
|
configProcessor = new ConfigProcessor(processingEnv);
|
||||||
for (TypeElement te : annotations) {
|
for (TypeElement te : annotations) {
|
||||||
Set<? extends Element> classes = roundEnv.getElementsAnnotatedWith(te);
|
Set<? extends Element> classes = roundEnv.getElementsAnnotatedWith(te);
|
||||||
for (Element targetcl : classes) {
|
for (Element targetcl : classes) {
|
||||||
System.out.println("Processing " + targetcl);
|
List<? extends AnnotationMirror> annotationMirrors = processingEnv.getElementUtils()
|
||||||
List<? extends AnnotationMirror> annotationMirrors = processingEnv.getElementUtils()
|
.getAllAnnotationMirrors(targetcl);
|
||||||
.getAllAnnotationMirrors(targetcl);
|
Function<String, Boolean> hasAnnotation = ann -> annotationMirrors.stream()
|
||||||
//System.out.println("Annotations: " + annotationMirrors);
|
.anyMatch(am -> am.getAnnotationType().toString().contains(ann));
|
||||||
Function<String, Boolean> hasAnnotation = ann -> annotationMirrors.stream()
|
if (hasAnnotation.apply("ChromaGamerEnforcer") && !hasAnnotation.apply("UserClass")
|
||||||
.anyMatch(am -> am.getAnnotationType().toString().contains(ann));
|
&& !targetcl.getModifiers().contains(Modifier.ABSTRACT))
|
||||||
if (hasAnnotation.apply("ChromaGamerEnforcer") && !hasAnnotation.apply("UserClass")
|
processingEnv.getMessager().printMessage(Kind.ERROR,
|
||||||
&& !targetcl.getModifiers().contains(Modifier.ABSTRACT))
|
"No UserClass annotation found for " + targetcl.getSimpleName(), targetcl);
|
||||||
processingEnv.getMessager().printMessage(Kind.ERROR,
|
if (hasAnnotation.apply("TBMCPlayerEnforcer") && !hasAnnotation.apply("PlayerClass")
|
||||||
"No UserClass annotation found for " + targetcl.getSimpleName(), targetcl);
|
&& !targetcl.getModifiers().contains(Modifier.ABSTRACT))
|
||||||
if (hasAnnotation.apply("TBMCPlayerEnforcer") && !hasAnnotation.apply("PlayerClass")
|
processingEnv.getMessager().printMessage(Kind.ERROR,
|
||||||
&& !targetcl.getModifiers().contains(Modifier.ABSTRACT))
|
"No PlayerClass annotation found for " + targetcl.getSimpleName(), targetcl);
|
||||||
processingEnv.getMessager().printMessage(Kind.ERROR,
|
processSubcommands(targetcl, annotationMirrors);
|
||||||
"No PlayerClass annotation found for " + targetcl.getSimpleName(), targetcl);
|
if (hasAnnotation.apply("HasConfig"))
|
||||||
for (AnnotationMirror annotation : annotationMirrors) {
|
configProcessor.process(targetcl);
|
||||||
String type = annotation.getAnnotationType().toString();
|
}
|
||||||
//System.out.println("Type: " + type);
|
}
|
||||||
}
|
|
||||||
processSubcommands(targetcl, annotationMirrors);
|
|
||||||
if (hasAnnotation.apply("HasConfig"))
|
|
||||||
configProcessor.process(targetcl);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
try {
|
try {
|
||||||
if (found) {
|
if (found) {
|
||||||
FileObject fo = processingEnv.getFiler().createResource(StandardLocation.CLASS_OUTPUT, "", "commands.yml");
|
FileObject fo = processingEnv.getFiler().createResource(StandardLocation.CLASS_OUTPUT, "", "commands.yml");
|
||||||
|
@ -59,38 +53,33 @@ public class ButtonProcessor extends AbstractProcessor {
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
e.printStackTrace();
|
e.printStackTrace();
|
||||||
}
|
}
|
||||||
return true; // claim the annotations
|
return true; // claim the annotations
|
||||||
}
|
}
|
||||||
|
|
||||||
private YamlConfiguration yc = new YamlConfiguration();
|
private final YamlConfiguration yc = new YamlConfiguration();
|
||||||
private boolean found = false;
|
private boolean found = false;
|
||||||
private ConfigProcessor configProcessor;
|
private ConfigProcessor configProcessor;
|
||||||
|
|
||||||
private void processSubcommands(Element targetcl, List<? extends AnnotationMirror> annotationMirrors) {
|
private void processSubcommands(Element method, List<? extends AnnotationMirror> annotationMirrors) {
|
||||||
if (!(targetcl instanceof ExecutableElement))
|
if (!(method instanceof ExecutableElement))
|
||||||
return;
|
return;
|
||||||
//System.out.println("Annotations: "+annotationMirrors);
|
|
||||||
if (annotationMirrors.stream().noneMatch(an -> an.getAnnotationType().toString().endsWith("Subcommand")))
|
if (annotationMirrors.stream().noneMatch(an -> an.getAnnotationType().toString().endsWith("Subcommand")))
|
||||||
return;
|
return;
|
||||||
//System.out.print("Processing method: " + targetcl.getEnclosingElement()+" "+targetcl);
|
ConfigurationSection cs = yc.createSection(method.getEnclosingElement().toString()
|
||||||
ConfigurationSection cs = yc.createSection(targetcl.getEnclosingElement().toString()
|
+ "." + method.getSimpleName().toString()); //Need to do the 2 config sections at once so it doesn't overwrite the class section
|
||||||
+ "." + targetcl.getSimpleName().toString()); //Need to do the 2 config sections at once so it doesn't overwrite the class section
|
System.out.println("Found subcommand: " + method);
|
||||||
System.out.println(targetcl);
|
cs.set("method", method.toString());
|
||||||
cs.set("method", targetcl.toString());
|
cs.set("params", ((ExecutableElement) method).getParameters().stream().skip(1).map(p -> {
|
||||||
cs.set("params", ((ExecutableElement) targetcl).getParameters().stream().skip(1).map(p -> {
|
|
||||||
//String tn=p.asType().toString();
|
|
||||||
//return tn.substring(tn.lastIndexOf('.')+1)+" "+p.getSimpleName();
|
|
||||||
boolean optional = p.getAnnotationMirrors().stream().anyMatch(am -> am.getAnnotationType().toString().endsWith("OptionalArg"));
|
boolean optional = p.getAnnotationMirrors().stream().anyMatch(am -> am.getAnnotationType().toString().endsWith("OptionalArg"));
|
||||||
if (optional)
|
if (optional)
|
||||||
return "[" + p.getSimpleName() + "]";
|
return "[" + p.getSimpleName() + "]";
|
||||||
return "<" + p.getSimpleName() + ">";
|
return "<" + p.getSimpleName() + ">";
|
||||||
}).collect(Collectors.joining(" ")));
|
}).collect(Collectors.joining(" ")));
|
||||||
//System.out.println();
|
|
||||||
found = true;
|
found = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public SourceVersion getSupportedSourceVersion() {
|
public SourceVersion getSupportedSourceVersion() {
|
||||||
return SourceVersion.latestSupported();
|
return SourceVersion.latestSupported();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,8 @@
|
||||||
package buttondevteam.buttonproc;
|
package buttondevteam.buttonproc;
|
||||||
|
|
||||||
|
import org.bukkit.configuration.InvalidConfigurationException;
|
||||||
|
import org.bukkit.configuration.file.YamlConfiguration;
|
||||||
|
|
||||||
import javax.annotation.processing.ProcessingEnvironment;
|
import javax.annotation.processing.ProcessingEnvironment;
|
||||||
import javax.lang.model.element.Element;
|
import javax.lang.model.element.Element;
|
||||||
import javax.lang.model.element.ExecutableElement;
|
import javax.lang.model.element.ExecutableElement;
|
||||||
|
@ -10,69 +13,67 @@ import javax.lang.model.type.TypeMirror;
|
||||||
import javax.tools.FileObject;
|
import javax.tools.FileObject;
|
||||||
import javax.tools.StandardLocation;
|
import javax.tools.StandardLocation;
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.io.FileWriter;
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
|
||||||
public class ConfigProcessor {
|
public class ConfigProcessor {
|
||||||
private final ProcessingEnvironment procEnv;
|
private final ProcessingEnvironment procEnv;
|
||||||
private final FileWriter sw;
|
private final YamlConfiguration yc = new YamlConfiguration();
|
||||||
|
private final FileObject fo;
|
||||||
|
|
||||||
public ConfigProcessor(ProcessingEnvironment procEnv) {
|
public ConfigProcessor(ProcessingEnvironment procEnv) {
|
||||||
|
FileObject fo1;
|
||||||
this.procEnv = procEnv;
|
this.procEnv = procEnv;
|
||||||
FileWriter sw = null;
|
|
||||||
try {
|
try {
|
||||||
FileObject file = procEnv.getFiler().createResource(StandardLocation.CLASS_OUTPUT, "", "configHelp.md");
|
fo1 = procEnv.getFiler().createResource(StandardLocation.CLASS_OUTPUT, "", "configHelp.yml");
|
||||||
sw = new FileWriter(new File(file.toUri()));
|
|
||||||
System.out.println(file.toUri());
|
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
e.printStackTrace();
|
e.printStackTrace();
|
||||||
|
fo1 = null;
|
||||||
}
|
}
|
||||||
this.sw = sw;
|
this.fo = fo1;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void process(Element targetcl) {
|
public void process(Element targetcl) {
|
||||||
if (targetcl.getModifiers().contains(Modifier.ABSTRACT)) return;
|
if (targetcl.getModifiers().contains(Modifier.ABSTRACT)) return;
|
||||||
final String path = "components." + targetcl.getSimpleName();
|
HasConfig hasConfig = targetcl.getAnnotation(HasConfig.class);
|
||||||
|
if (hasConfig == null) {
|
||||||
|
System.out.println("That's not our HasConfig annotation...");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
final String path = hasConfig.global() ? "global" : "components." + targetcl.getSimpleName();
|
||||||
|
File file = new File(fo.toUri());
|
||||||
|
try {
|
||||||
|
if (file.exists())
|
||||||
|
yc.load(file);
|
||||||
|
} catch (IOException | InvalidConfigurationException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
for (Element e : targetcl.getEnclosedElements()) {
|
for (Element e : targetcl.getEnclosedElements()) {
|
||||||
/*System.out.println("Element: "+e);
|
TypeMirror tm;
|
||||||
System.out.println("Type: "+e.getClass()+" - "+e.getKind());
|
if (e instanceof ExecutableElement)
|
||||||
if(e instanceof ExecutableElement)
|
tm = ((ExecutableElement) e).getReturnType();
|
||||||
System.out.println("METHOD!");*/
|
else if (e.getKind().isField())
|
||||||
if (!(e instanceof ExecutableElement)) continue;
|
tm = e.asType();
|
||||||
TypeMirror tm = ((ExecutableElement) e).getReturnType();
|
else
|
||||||
|
continue;
|
||||||
if (tm.getKind() != TypeKind.DECLARED) continue;
|
if (tm.getKind() != TypeKind.DECLARED) continue;
|
||||||
DeclaredType dt = (DeclaredType) tm;
|
DeclaredType dt = (DeclaredType) tm;
|
||||||
if (!dt.asElement().getSimpleName().contentEquals("ConfigData"))
|
if (!dt.asElement().getSimpleName().toString().contains("ConfigData"))
|
||||||
continue; //Ahhha! There was a return here! (MinecraftChatModule getListener())
|
continue; //Ahhha! There was a return here! (MinecraftChatModule getListener())
|
||||||
System.out.println("Config: " + e.getSimpleName());
|
|
||||||
|
|
||||||
String doc = procEnv.getElementUtils().getDocComment(e);
|
String doc = procEnv.getElementUtils().getDocComment(e);
|
||||||
if (doc == null) continue;
|
if (doc == null) continue;
|
||||||
System.out.println("DOC: " + doc);
|
System.out.println("Adding docs for config: " + e.getSimpleName());
|
||||||
try {
|
yc.set(path + "." + e.getSimpleName(), doc.trim());
|
||||||
sw.append(path).append(".").append(String.valueOf(e.getSimpleName())).append(System.lineSeparator()).append(System.lineSeparator());
|
|
||||||
sw.append(doc.trim()).append(System.lineSeparator()).append(System.lineSeparator());
|
|
||||||
} catch (IOException e1) {
|
|
||||||
e1.printStackTrace();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
String javadoc = procEnv.getElementUtils().getDocComment(targetcl);
|
String javadoc = procEnv.getElementUtils().getDocComment(targetcl);
|
||||||
|
if (javadoc != null) {
|
||||||
|
System.out.println("Adding docs for class: " + targetcl.getSimpleName());
|
||||||
|
yc.set(path + ".generalDescriptionInsteadOfAConfig", javadoc.trim());
|
||||||
|
}
|
||||||
try {
|
try {
|
||||||
if (javadoc != null) {
|
yc.save(file);
|
||||||
System.out.println("JAVADOC");
|
|
||||||
System.out.println(javadoc.trim());
|
|
||||||
sw.append(path).append(System.lineSeparator()).append(System.lineSeparator());
|
|
||||||
sw.append(javadoc).append(System.lineSeparator()).append(System.lineSeparator());
|
|
||||||
}
|
|
||||||
sw.flush();
|
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
e.printStackTrace();
|
e.printStackTrace();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void finalize() throws Throwable {
|
|
||||||
sw.close();
|
|
||||||
super.finalize();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
package buttondevteam.lib.architecture;
|
package buttondevteam.buttonproc;
|
||||||
|
|
||||||
import java.lang.annotation.ElementType;
|
import java.lang.annotation.ElementType;
|
||||||
import java.lang.annotation.Inherited;
|
import java.lang.annotation.Inherited;
|
||||||
|
@ -10,4 +10,5 @@ import java.lang.annotation.Target;
|
||||||
@Target(ElementType.TYPE)
|
@Target(ElementType.TYPE)
|
||||||
@Inherited
|
@Inherited
|
||||||
public @interface HasConfig {
|
public @interface HasConfig {
|
||||||
|
boolean global();
|
||||||
}
|
}
|
|
@ -1,15 +1,16 @@
|
||||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||||
<modelVersion>4.0.0</modelVersion>
|
<modelVersion>4.0.0</modelVersion>
|
||||||
<parent>
|
<parent>
|
||||||
<groupId>com.github.TBMCPlugins</groupId>
|
<groupId>com.github.TBMCPlugins.ChromaCore</groupId>
|
||||||
<artifactId>ButtonCore</artifactId>
|
<artifactId>CorePOM</artifactId>
|
||||||
<version>master-SNAPSHOT</version>
|
<version>master-SNAPSHOT</version>
|
||||||
</parent>
|
<relativePath>../CorePOM</relativePath>
|
||||||
<groupId>com.github.TBMCPlugins.ButtonCore</groupId>
|
</parent>
|
||||||
<artifactId>ButtonCore</artifactId>
|
<artifactId>Chroma-Core</artifactId>
|
||||||
<name>ButtonCore</name>
|
<name>Chroma-Core</name>
|
||||||
<description>ButtonCore</description>
|
<description>Chroma-Core</description>
|
||||||
|
<version>v${noprefix.version}-SNAPSHOT</version>
|
||||||
<build>
|
<build>
|
||||||
<sourceDirectory>src/main/java</sourceDirectory>
|
<sourceDirectory>src/main/java</sourceDirectory>
|
||||||
<resources>
|
<resources>
|
||||||
|
@ -24,29 +25,33 @@
|
||||||
<filtering>true</filtering>
|
<filtering>true</filtering>
|
||||||
</resource>
|
</resource>
|
||||||
</resources>
|
</resources>
|
||||||
<finalName>ButtonCore</finalName>
|
<finalName>Chroma-Core</finalName>
|
||||||
<plugins>
|
<plugins>
|
||||||
<plugin>
|
|
||||||
<artifactId>maven-compiler-plugin</artifactId>
|
|
||||||
<configuration>
|
|
||||||
<source>1.8</source>
|
|
||||||
<target>1.8</target>
|
|
||||||
</configuration>
|
|
||||||
</plugin>
|
|
||||||
<plugin>
|
<plugin>
|
||||||
<groupId>org.apache.maven.plugins</groupId>
|
<groupId>org.apache.maven.plugins</groupId>
|
||||||
<artifactId>maven-shade-plugin</artifactId>
|
<artifactId>maven-shade-plugin</artifactId>
|
||||||
<version>2.4.2</version>
|
<version>3.2.1</version>
|
||||||
<executions>
|
<executions>
|
||||||
<execution>
|
<execution>
|
||||||
<phase>package</phase>
|
<phase>package</phase>
|
||||||
<goals>
|
<goals>
|
||||||
<goal>shade</goal>
|
<goal>shade</goal>
|
||||||
</goals>
|
</goals>
|
||||||
<configuration>
|
<configuration>
|
||||||
<artifactSet>
|
<artifactSet>
|
||||||
</artifactSet>
|
<includes>
|
||||||
</configuration>
|
<include>me.lucko:commodore</include>
|
||||||
|
<include>org.javatuples:javatuples</include>
|
||||||
|
</includes>
|
||||||
|
</artifactSet>
|
||||||
|
<relocations>
|
||||||
|
<relocation>
|
||||||
|
<pattern>me.lucko.commodore</pattern>
|
||||||
|
<!-- vvv Replace with the package of your plugin vvv -->
|
||||||
|
<shadedPattern>buttondevteam.core.commodore</shadedPattern>
|
||||||
|
</relocation>
|
||||||
|
</relocations>
|
||||||
|
</configuration>
|
||||||
</execution>
|
</execution>
|
||||||
</executions>
|
</executions>
|
||||||
</plugin>
|
</plugin>
|
||||||
|
@ -68,6 +73,7 @@
|
||||||
<directory>src/main/resources</directory>
|
<directory>src/main/resources</directory>
|
||||||
</resource>
|
</resource>
|
||||||
</resources>
|
</resources>
|
||||||
|
<encoding>UTF-8</encoding>
|
||||||
</configuration>
|
</configuration>
|
||||||
</execution>
|
</execution>
|
||||||
</executions>
|
</executions>
|
||||||
|
@ -111,18 +117,22 @@
|
||||||
</repository> -->
|
</repository> -->
|
||||||
<repository>
|
<repository>
|
||||||
<id>ess-repo</id>
|
<id>ess-repo</id>
|
||||||
<url>http://repo.ess3.net/content/repositories/essrel/</url>
|
<url>https://ci.ender.zone/plugin/repository/everything/</url>
|
||||||
</repository>
|
|
||||||
<repository>
|
|
||||||
<id>Votifier</id>
|
|
||||||
<url>https://dl.bintray.com/nuvotifier/maven/</url>
|
|
||||||
</repository>
|
</repository>
|
||||||
</repositories>
|
<repository>
|
||||||
|
<id>Multiverse-Core</id>
|
||||||
|
<url>https://repo.onarandombox.com/content/groups/public/</url>
|
||||||
|
</repository>
|
||||||
|
<repository>
|
||||||
|
<id>minecraft-repo</id>
|
||||||
|
<url>https://libraries.minecraft.net/</url>
|
||||||
|
</repository>
|
||||||
|
</repositories>
|
||||||
<dependencies>
|
<dependencies>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.reflections</groupId>
|
<groupId>org.reflections</groupId>
|
||||||
<artifactId>reflections</artifactId>
|
<artifactId>reflections</artifactId>
|
||||||
<version>0.9.10</version>
|
<version>0.10.2</version>
|
||||||
<scope>compile</scope>
|
<scope>compile</scope>
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
|
@ -131,18 +141,10 @@
|
||||||
<version>1.12.2-R0.1-SNAPSHOT</version>
|
<version>1.12.2-R0.1-SNAPSHOT</version>
|
||||||
<scope>provided</scope>
|
<scope>provided</scope>
|
||||||
</dependency>
|
</dependency>
|
||||||
<!-- https://mvnrepository.com/artifact/org.apache.commons/commons-io -->
|
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>commons-io</groupId>
|
<groupId>com.github.TownyAdvanced</groupId>
|
||||||
<artifactId>commons-io</artifactId>
|
|
||||||
<version>1.3.2</version>
|
|
||||||
<scope>provided</scope>
|
|
||||||
</dependency>
|
|
||||||
<!-- Change jitpack.yml to set location of Towny JAR -->
|
|
||||||
<dependency>
|
|
||||||
<groupId>com.github.TBMCPlugins.ButtonCore</groupId>
|
|
||||||
<artifactId>Towny</artifactId>
|
<artifactId>Towny</artifactId>
|
||||||
<version>master-SNAPSHOT</version>
|
<version>0.94.0.9</version>
|
||||||
<scope>provided</scope>
|
<scope>provided</scope>
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
|
@ -155,38 +157,49 @@
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.javassist</groupId>
|
<groupId>org.javassist</groupId>
|
||||||
<artifactId>javassist</artifactId>
|
<artifactId>javassist</artifactId>
|
||||||
<version>3.20.0-GA</version>
|
<version>3.28.0-GA</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.mockito</groupId>
|
<groupId>org.mockito</groupId>
|
||||||
<artifactId>mockito-core</artifactId>
|
<artifactId>mockito-core</artifactId>
|
||||||
<version>2.7.20</version>
|
<version>4.2.0</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>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>com.github.TBMCPlugins.ButtonCore</groupId>
|
<groupId>com.github.TBMCPlugins.ChromaCore</groupId>
|
||||||
<artifactId>ButtonProcessor</artifactId>
|
<artifactId>ButtonProcessor</artifactId>
|
||||||
<version>master-SNAPSHOT</version>
|
<version>master-SNAPSHOT</version>
|
||||||
<scope>compile</scope>
|
<scope>compile</scope>
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>net.ess3</groupId>
|
<groupId>net.ess3</groupId>
|
||||||
<artifactId>Essentials</artifactId>
|
<artifactId>EssentialsX</artifactId>
|
||||||
<version>2.13.1</version>
|
<version>2.17.1</version>
|
||||||
<scope>provided</scope>
|
<scope>provided</scope>
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
<!-- https://mvnrepository.com/artifact/com.github.NuVotifier.NuVotifier/nuvotifier-bukkit -->
|
||||||
<groupId>com.vexsoftware</groupId>
|
<dependency>
|
||||||
<artifactId>nuvotifier-universal</artifactId>
|
<groupId>com.github.NuVotifier.NuVotifier</groupId>
|
||||||
<version>2.3.4</version>
|
<artifactId>nuvotifier-bukkit</artifactId>
|
||||||
<scope>provided</scope>
|
<version>v2.7.1</version>
|
||||||
</dependency>
|
<scope>provided</scope>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.onarandombox.multiversecore</groupId>
|
||||||
|
<artifactId>Multiverse-Core</artifactId>
|
||||||
|
<version>4.3.1</version>
|
||||||
|
<scope>provided</scope>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>me.lucko</groupId>
|
||||||
|
<artifactId>commodore</artifactId>
|
||||||
|
<version>1.11</version>
|
||||||
|
<scope>compile</scope>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.javatuples</groupId>
|
||||||
|
<artifactId>javatuples</artifactId>
|
||||||
|
<version>1.2</version>
|
||||||
|
</dependency>
|
||||||
</dependencies>
|
</dependencies>
|
||||||
<organization>
|
<organization>
|
||||||
<name>TBMCPlugins</name>
|
<name>TBMCPlugins</name>
|
||||||
|
@ -203,10 +216,11 @@
|
||||||
<!-- github server corresponds to entry in ~/.m2/settings.xml -->
|
<!-- github server corresponds to entry in ~/.m2/settings.xml -->
|
||||||
<github.global.server>github</github.global.server>
|
<github.global.server>github</github.global.server>
|
||||||
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||||
|
<noprefix.version>1.0.1</noprefix.version>
|
||||||
</properties>
|
</properties>
|
||||||
<scm>
|
<scm>
|
||||||
<url>https://github.com/TBMCPlugins/mvn-repo</url>
|
<url>https://github.com/TBMCPlugins/mvn-repo</url>
|
||||||
<connection>scm:git:https://github.com/TBMCPlugins/mvn-repo.git</connection>
|
<connection>scm:git:https://github.com/TBMCPlugins/mvn-repo.git</connection>
|
||||||
<developerConnection>scm:git:https://github.com/TBMCPlugins/mvn-repo.git</developerConnection>
|
<developerConnection>scm:git:https://github.com/TBMCPlugins/mvn-repo.git</developerConnection>
|
||||||
</scm>
|
</scm>
|
||||||
</project>
|
</project>
|
|
@ -0,0 +1,38 @@
|
||||||
|
package buttondevteam.core;
|
||||||
|
|
||||||
|
import buttondevteam.lib.architecture.ButtonPlugin;
|
||||||
|
import buttondevteam.lib.chat.Command2;
|
||||||
|
import buttondevteam.lib.chat.CommandClass;
|
||||||
|
import buttondevteam.lib.chat.ICommand2MC;
|
||||||
|
import org.bukkit.Bukkit;
|
||||||
|
import org.bukkit.command.CommandSender;
|
||||||
|
import org.bukkit.plugin.Plugin;
|
||||||
|
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.Optional;
|
||||||
|
|
||||||
|
@CommandClass
|
||||||
|
public class ChromaCommand extends ICommand2MC {
|
||||||
|
public ChromaCommand() {
|
||||||
|
getManager().addParamConverter(ButtonPlugin.class, name ->
|
||||||
|
(ButtonPlugin) Optional.ofNullable(Bukkit.getPluginManager().getPlugin(name))
|
||||||
|
.filter(plugin -> plugin instanceof ButtonPlugin).orElse(null),
|
||||||
|
"No Chroma plugin found by that name.", () -> Arrays.stream(Bukkit.getPluginManager().getPlugins())
|
||||||
|
.filter(plugin -> plugin instanceof ButtonPlugin).map(Plugin::getName)::iterator);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Command2.Subcommand
|
||||||
|
public void reload(CommandSender sender, @Command2.OptionalArg ButtonPlugin plugin) {
|
||||||
|
if (plugin == null)
|
||||||
|
plugin = MainPlugin.Instance;
|
||||||
|
if (plugin.tryReloadConfig())
|
||||||
|
sender.sendMessage("§b" + plugin.getName() + " config reloaded.");
|
||||||
|
else
|
||||||
|
sender.sendMessage("§cFailed to reload config. Check console.");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Command2.Subcommand
|
||||||
|
public void def(CommandSender sender) {
|
||||||
|
sender.sendMessage(ButtonPlugin.getCommand2MC().getCommandsText());
|
||||||
|
}
|
||||||
|
}
|
|
@ -6,13 +6,17 @@ import buttondevteam.lib.architecture.Component;
|
||||||
import buttondevteam.lib.chat.Command2;
|
import buttondevteam.lib.chat.Command2;
|
||||||
import buttondevteam.lib.chat.Command2.Subcommand;
|
import buttondevteam.lib.chat.Command2.Subcommand;
|
||||||
import buttondevteam.lib.chat.CommandClass;
|
import buttondevteam.lib.chat.CommandClass;
|
||||||
|
import buttondevteam.lib.chat.CustomTabCompleteMethod;
|
||||||
import buttondevteam.lib.chat.ICommand2MC;
|
import buttondevteam.lib.chat.ICommand2MC;
|
||||||
import lombok.val;
|
import lombok.val;
|
||||||
import org.bukkit.Bukkit;
|
import org.bukkit.Bukkit;
|
||||||
import org.bukkit.command.CommandSender;
|
import org.bukkit.command.CommandSender;
|
||||||
import org.bukkit.plugin.Plugin;
|
import org.bukkit.plugin.Plugin;
|
||||||
|
import org.bukkit.plugin.java.JavaPlugin;
|
||||||
|
|
||||||
|
import java.util.Arrays;
|
||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
|
import java.util.stream.Stream;
|
||||||
|
|
||||||
@CommandClass(modOnly = true, helpText = {
|
@CommandClass(modOnly = true, helpText = {
|
||||||
"Component command",
|
"Component command",
|
||||||
|
@ -20,24 +24,37 @@ import java.util.Optional;
|
||||||
})
|
})
|
||||||
public class ComponentCommand extends ICommand2MC {
|
public class ComponentCommand extends ICommand2MC {
|
||||||
public ComponentCommand() {
|
public ComponentCommand() {
|
||||||
getManager().addParamConverter(Plugin.class, arg -> Bukkit.getPluginManager().getPlugin(arg), "Plugin not found!");
|
getManager().addParamConverter(Plugin.class, arg -> Bukkit.getPluginManager().getPlugin(arg), "Plugin not found!",
|
||||||
|
() -> Arrays.stream(Bukkit.getPluginManager().getPlugins()).map(Plugin::getName)::iterator);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Subcommand
|
@Subcommand(helpText = {
|
||||||
public boolean enable(CommandSender sender, Plugin plugin, String component) {
|
"Enable component",
|
||||||
if (plugin instanceof ButtonPlugin)
|
"Temporarily or permanently enables a component."
|
||||||
((ButtonPlugin) plugin).justReload();
|
})
|
||||||
else
|
public boolean enable(CommandSender sender, Plugin plugin, String component, @Command2.OptionalArg boolean permanent) {
|
||||||
|
if (plugin instanceof ButtonPlugin) {
|
||||||
|
if (!((ButtonPlugin) plugin).justReload()) {
|
||||||
|
sender.sendMessage("§cCouldn't reload config, check console.");
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
} else
|
||||||
plugin.reloadConfig(); //Reload config so the new config values are read - All changes are saved to disk on disable
|
plugin.reloadConfig(); //Reload config so the new config values are read - All changes are saved to disk on disable
|
||||||
return enable_disable(sender, plugin, component, true);
|
return enable_disable(sender, plugin, component, true, permanent);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Subcommand
|
@Subcommand(helpText = {
|
||||||
public boolean disable(CommandSender sender, Plugin plugin, String component) {
|
"Disable component",
|
||||||
return enable_disable(sender, plugin, component, false);
|
"Temporarily or permanently disables a component."
|
||||||
|
})
|
||||||
|
public boolean disable(CommandSender sender, Plugin plugin, String component, @Command2.OptionalArg boolean permanent) {
|
||||||
|
return enable_disable(sender, plugin, component, false, permanent);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Subcommand
|
@Subcommand(helpText = {
|
||||||
|
"List components",
|
||||||
|
"Lists all of the registered Chroma components"
|
||||||
|
})
|
||||||
public boolean list(CommandSender sender, @Command2.OptionalArg String plugin) {
|
public boolean list(CommandSender sender, @Command2.OptionalArg String plugin) {
|
||||||
sender.sendMessage("§6List of components:");
|
sender.sendMessage("§6List of components:");
|
||||||
Component.getComponents().values().stream().filter(c -> plugin == null || c.getPlugin().getName().equalsIgnoreCase(plugin)) //If plugin is null, don't check
|
Component.getComponents().values().stream().filter(c -> plugin == null || c.getPlugin().getName().equalsIgnoreCase(plugin)) //If plugin is null, don't check
|
||||||
|
@ -45,25 +62,41 @@ public class ComponentCommand extends ICommand2MC {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean enable_disable(CommandSender sender, Plugin plugin, String component, boolean enable) {
|
@CustomTabCompleteMethod(param = "component", subcommand = {"enable", "disable"})
|
||||||
|
public Iterable<String> componentTabcomplete(Plugin plugin) {
|
||||||
|
return getPluginComponents(plugin).map(c -> c.getClass().getSimpleName())::iterator;
|
||||||
|
}
|
||||||
|
|
||||||
|
@CustomTabCompleteMethod(param = "plugin", subcommand = {"list", "enable", "disable"}, ignoreTypeCompletion = true)
|
||||||
|
public Iterable<String> pluginTabcomplete() {
|
||||||
|
return Component.getComponents().values().stream().map(Component::getPlugin)
|
||||||
|
.distinct().map(Plugin::getName)::iterator;
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean enable_disable(CommandSender sender, Plugin plugin, String component, boolean enable, boolean permanent) {
|
||||||
try {
|
try {
|
||||||
val oc = getComponentOrError(plugin, component, sender);
|
val oc = getComponentOrError(plugin, component, sender);
|
||||||
if (!oc.isPresent())
|
if (!oc.isPresent())
|
||||||
return true;
|
return true;
|
||||||
Component.setComponentEnabled(oc.get(), enable);
|
Component.setComponentEnabled(oc.get(), enable);
|
||||||
sender.sendMessage(oc.get().getClass().getSimpleName() + " " + (enable ? "en" : "dis") + "abled.");
|
if (permanent)
|
||||||
|
oc.get().shouldBeEnabled.set(enable);
|
||||||
|
sender.sendMessage(oc.get().getClass().getSimpleName() + " " + (enable ? "en" : "dis") + "abled " + (permanent ? "permanently" : "temporarily") + ".");
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
TBMCCoreAPI.SendException("Couldn't " + (enable ? "en" : "dis") + "able component " + component + "!", e);
|
TBMCCoreAPI.SendException("Couldn't " + (enable ? "en" : "dis") + "able component " + component + "!", e, (JavaPlugin) plugin);
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private Stream<Component<? extends JavaPlugin>> getPluginComponents(Plugin plugin) {
|
||||||
|
return Component.getComponents().values().stream()
|
||||||
|
.filter(c -> plugin.getName().equals(c.getPlugin().getName()));
|
||||||
|
}
|
||||||
|
|
||||||
private Optional<Component<?>> getComponentOrError(Plugin plugin, String arg, CommandSender sender) {
|
private Optional<Component<?>> getComponentOrError(Plugin plugin, String arg, CommandSender sender) {
|
||||||
val oc = Component.getComponents().values().stream()
|
val oc = getPluginComponents(plugin).filter(c -> c.getClass().getSimpleName().equalsIgnoreCase(arg)).findAny();
|
||||||
.filter(c -> plugin.getName().equals(c.getPlugin().getName()))
|
|
||||||
.filter(c -> c.getClass().getSimpleName().equalsIgnoreCase(arg)).findAny();
|
|
||||||
if (!oc.isPresent())
|
if (!oc.isPresent())
|
||||||
sender.sendMessage("§cComponent not found!"); //^ Much simpler to solve in the new command system
|
sender.sendMessage("§cComponent not found!"); //^ Much simpler to solve in the new command system
|
||||||
return oc;
|
return oc;
|
||||||
} //TODO: Tabcompletion for the new command system
|
}
|
||||||
}
|
}
|
|
@ -21,11 +21,11 @@ public final class ComponentManager {
|
||||||
*/
|
*/
|
||||||
public static void enableComponents() {
|
public static void enableComponents() {
|
||||||
//Component.getComponents().values().stream().filter(c->cs.getConfigurationSection(c.getClass().getSimpleName()).getBoolean("enabled")).forEach(c-> {
|
//Component.getComponents().values().stream().filter(c->cs.getConfigurationSection(c.getClass().getSimpleName()).getBoolean("enabled")).forEach(c-> {
|
||||||
Component.getComponents().values().stream().filter(c -> c.shouldBeEnabled().get()).forEach(c -> {
|
Component.getComponents().values().stream().filter(c -> c.shouldBeEnabled.get()).forEach(c -> {
|
||||||
try {
|
try {
|
||||||
Component.setComponentEnabled(c, true);
|
Component.setComponentEnabled(c, true);
|
||||||
} catch (Exception e) {
|
} catch (Exception | NoClassDefFoundError e) {
|
||||||
TBMCCoreAPI.SendException("Failed to enable one of the components: " + c.getClass().getSimpleName(), e);
|
TBMCCoreAPI.SendException("Failed to enable one of the components: " + c.getClass().getSimpleName(), e, c);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
componentsEnabled = true;
|
componentsEnabled = true;
|
|
@ -6,10 +6,8 @@ import buttondevteam.core.component.channel.ChatRoom;
|
||||||
import buttondevteam.core.component.members.MemberComponent;
|
import buttondevteam.core.component.members.MemberComponent;
|
||||||
import buttondevteam.core.component.randomtp.RandomTPComponent;
|
import buttondevteam.core.component.randomtp.RandomTPComponent;
|
||||||
import buttondevteam.core.component.restart.RestartComponent;
|
import buttondevteam.core.component.restart.RestartComponent;
|
||||||
|
import buttondevteam.core.component.spawn.SpawnComponent;
|
||||||
import buttondevteam.core.component.towny.TownyComponent;
|
import buttondevteam.core.component.towny.TownyComponent;
|
||||||
import buttondevteam.core.component.updater.PluginUpdater;
|
|
||||||
import buttondevteam.core.component.updater.PluginUpdaterComponent;
|
|
||||||
import buttondevteam.core.component.votifier.VotifierComponent;
|
|
||||||
import buttondevteam.lib.TBMCCoreAPI;
|
import buttondevteam.lib.TBMCCoreAPI;
|
||||||
import buttondevteam.lib.architecture.ButtonPlugin;
|
import buttondevteam.lib.architecture.ButtonPlugin;
|
||||||
import buttondevteam.lib.architecture.Component;
|
import buttondevteam.lib.architecture.Component;
|
||||||
|
@ -25,10 +23,12 @@ import lombok.Setter;
|
||||||
import net.milkbowl.vault.economy.Economy;
|
import net.milkbowl.vault.economy.Economy;
|
||||||
import net.milkbowl.vault.permission.Permission;
|
import net.milkbowl.vault.permission.Permission;
|
||||||
import org.bukkit.Bukkit;
|
import org.bukkit.Bukkit;
|
||||||
|
import org.bukkit.OfflinePlayer;
|
||||||
import org.bukkit.command.BlockCommandSender;
|
import org.bukkit.command.BlockCommandSender;
|
||||||
import org.bukkit.command.Command;
|
import org.bukkit.command.Command;
|
||||||
import org.bukkit.command.CommandSender;
|
import org.bukkit.command.CommandSender;
|
||||||
import org.bukkit.command.ConsoleCommandSender;
|
import org.bukkit.command.ConsoleCommandSender;
|
||||||
|
import org.bukkit.entity.HumanEntity;
|
||||||
import org.bukkit.entity.Player;
|
import org.bukkit.entity.Player;
|
||||||
import org.bukkit.plugin.PluginDescriptionFile;
|
import org.bukkit.plugin.PluginDescriptionFile;
|
||||||
import org.bukkit.plugin.RegisteredServiceProvider;
|
import org.bukkit.plugin.RegisteredServiceProvider;
|
||||||
|
@ -37,15 +37,16 @@ import javax.annotation.Nullable;
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.nio.file.Files;
|
import java.nio.file.Files;
|
||||||
import java.nio.file.StandardCopyOption;
|
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
|
import java.util.function.Supplier;
|
||||||
import java.util.logging.Logger;
|
import java.util.logging.Logger;
|
||||||
|
|
||||||
public class MainPlugin extends ButtonPlugin {
|
public class MainPlugin extends ButtonPlugin {
|
||||||
public static MainPlugin Instance;
|
public static MainPlugin Instance;
|
||||||
public static Permission permission;
|
public static Permission permission;
|
||||||
|
@Nullable
|
||||||
public static Essentials ess;
|
public static Essentials ess;
|
||||||
|
|
||||||
private Logger logger;
|
private Logger logger;
|
||||||
|
@ -59,49 +60,58 @@ public class MainPlugin extends ButtonPlugin {
|
||||||
@Setter
|
@Setter
|
||||||
private boolean chatHandlerEnabled = true;
|
private boolean chatHandlerEnabled = true;
|
||||||
|
|
||||||
private ConfigData<Boolean> writePluginList() {
|
/**
|
||||||
return getIConfig().getData("writePluginList", false);
|
* Sets whether the plugin should write a list of installed plugins in a txt file.
|
||||||
}
|
* It can be useful if some other software needs to know the plugins.
|
||||||
|
*/
|
||||||
|
private final ConfigData<Boolean> writePluginList = getIConfig().getData("writePluginList", false);
|
||||||
|
|
||||||
ConfigData<String> chatFormat() {
|
/**
|
||||||
return getIConfig().getData("chatFormat", "[{origin}|" +
|
* The chat format to use for messages from other platforms if Chroma-Chat is not installed.
|
||||||
"{channel}] <{name}> {message}");
|
*/
|
||||||
}
|
ConfigData<String> chatFormat = getIConfig().getData("chatFormat", "[{origin}|" +
|
||||||
|
"{channel}] <{name}> {message}");
|
||||||
|
|
||||||
public ConfigData<Boolean> test() {
|
/**
|
||||||
return getIConfig().getData("test", true);
|
* Print some debug information.
|
||||||
}
|
*/
|
||||||
|
public final ConfigData<Boolean> test = getIConfig().getData("test", false);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* If a Chroma command clashes with another plugin's command, this setting determines whether the Chroma command should be executed or the other plugin's.
|
||||||
|
*/
|
||||||
|
public final ConfigData<Boolean> prioritizeCustomCommands = getIConfig().getData("prioritizeCustomCommands", false);
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void pluginEnable() {
|
public void pluginEnable() {
|
||||||
// Logs "Plugin Enabled", registers commands
|
|
||||||
Instance = this;
|
Instance = this;
|
||||||
PluginDescriptionFile pdf = getDescription();
|
PluginDescriptionFile pdf = getDescription();
|
||||||
logger = getLogger();
|
logger = getLogger();
|
||||||
if (!setupPermissions())
|
if (!setupPermissions())
|
||||||
throw new NullPointerException("No permission plugin found!");
|
throw new NullPointerException("No permission plugin found!");
|
||||||
if (!setupEconomy()) //Though Essentials always provides economy so this shouldn't happen
|
if (!setupEconomy()) //Though Essentials always provides economy, but we don't require Essentials
|
||||||
getLogger().warning("No economy plugin found! Components using economy will not be registered.");
|
getLogger().warning("No economy plugin found! Components using economy will not be registered.");
|
||||||
saveConfig();
|
saveConfig();
|
||||||
Component.registerComponent(this, new PluginUpdaterComponent());
|
|
||||||
Component.registerComponent(this, new RestartComponent());
|
Component.registerComponent(this, new RestartComponent());
|
||||||
//noinspection unchecked - needed for testing
|
|
||||||
Component.registerComponent(this, new ChannelComponent());
|
Component.registerComponent(this, new ChannelComponent());
|
||||||
Component.registerComponent(this, new RandomTPComponent());
|
Component.registerComponent(this, new RandomTPComponent());
|
||||||
Component.registerComponent(this, new MemberComponent());
|
Component.registerComponent(this, new MemberComponent());
|
||||||
|
if (Bukkit.getPluginManager().isPluginEnabled("Multiverse-Core"))
|
||||||
|
Component.registerComponent(this, new SpawnComponent());
|
||||||
if (Bukkit.getPluginManager().isPluginEnabled("Towny")) //It fails to load the component class otherwise
|
if (Bukkit.getPluginManager().isPluginEnabled("Towny")) //It fails to load the component class otherwise
|
||||||
Component.registerComponent(this, new TownyComponent());
|
Component.registerComponent(this, new TownyComponent());
|
||||||
if (Bukkit.getPluginManager().isPluginEnabled("Votifier") && economy != null)
|
/*if (Bukkit.getPluginManager().isPluginEnabled("Votifier") && economy != null)
|
||||||
Component.registerComponent(this, new VotifierComponent(economy));
|
Component.registerComponent(this, new VotifierComponent(economy));*/
|
||||||
ComponentManager.enableComponents();
|
ComponentManager.enableComponents();
|
||||||
getCommand2MC().registerCommand(new ComponentCommand());
|
registerCommand(new ComponentCommand());
|
||||||
getCommand2MC().registerCommand(new ThorpeCommand());
|
registerCommand(new ChromaCommand());
|
||||||
TBMCCoreAPI.RegisterEventsForExceptions(new PlayerListener(), this);
|
TBMCCoreAPI.RegisterEventsForExceptions(new PlayerListener(), this);
|
||||||
|
TBMCCoreAPI.RegisterEventsForExceptions(getCommand2MC(), this);
|
||||||
ChromaGamerBase.addConverter(commandSender -> Optional.ofNullable(commandSender instanceof ConsoleCommandSender || commandSender instanceof BlockCommandSender
|
ChromaGamerBase.addConverter(commandSender -> Optional.ofNullable(commandSender instanceof ConsoleCommandSender || commandSender instanceof BlockCommandSender
|
||||||
? TBMCPlayer.getPlayer(new UUID(0, 0), TBMCPlayer.class) : null)); //Console & cmdblocks
|
? TBMCPlayer.getPlayer(new UUID(0, 0), TBMCPlayer.class) : null)); //Console & cmdblocks
|
||||||
ChromaGamerBase.addConverter(sender -> Optional.ofNullable(sender instanceof Player
|
ChromaGamerBase.addConverter(sender -> Optional.ofNullable(sender instanceof Player
|
||||||
? TBMCPlayer.getPlayer(((Player) sender).getUniqueId(), TBMCPlayer.class) : null)); //Players, has higher priority
|
? TBMCPlayer.getPlayer(((Player) sender).getUniqueId(), TBMCPlayer.class) : null)); //Players, has higher priority
|
||||||
TBMCCoreAPI.RegisterUserClass(TBMCPlayerBase.class);
|
TBMCCoreAPI.RegisterUserClass(TBMCPlayerBase.class, TBMCPlayer::new);
|
||||||
TBMCChatAPI.RegisterChatChannel(Channel.GlobalChat = new Channel("§fg§f", Color.White, "g", null)); //The /ooc ID has moved to the config
|
TBMCChatAPI.RegisterChatChannel(Channel.GlobalChat = new Channel("§fg§f", Color.White, "g", null)); //The /ooc ID has moved to the config
|
||||||
TBMCChatAPI.RegisterChatChannel(
|
TBMCChatAPI.RegisterChatChannel(
|
||||||
Channel.AdminChat = new Channel("§cADMIN§f", Color.Red, "a", Channel.inGroupFilter(null)));
|
Channel.AdminChat = new Channel("§cADMIN§f", Color.Red, "a", Channel.inGroupFilter(null)));
|
||||||
|
@ -114,37 +124,26 @@ public class MainPlugin extends ButtonPlugin {
|
||||||
TBMCChatAPI.RegisterChatChannel(new ChatRoom("§aGREEN§f", Color.Green, "green"));
|
TBMCChatAPI.RegisterChatChannel(new ChatRoom("§aGREEN§f", Color.Green, "green"));
|
||||||
TBMCChatAPI.RegisterChatChannel(new ChatRoom("§bBLUE§f", Color.Blue, "blue"));
|
TBMCChatAPI.RegisterChatChannel(new ChatRoom("§bBLUE§f", Color.Blue, "blue"));
|
||||||
TBMCChatAPI.RegisterChatChannel(new ChatRoom("§5PURPLE§f", Color.DarkPurple, "purple"));
|
TBMCChatAPI.RegisterChatChannel(new ChatRoom("§5PURPLE§f", Color.DarkPurple, "purple"));
|
||||||
if (writePluginList().get()) {
|
Supplier<Iterable<String>> playerSupplier = () -> Bukkit.getOnlinePlayers().stream().map(HumanEntity::getName)::iterator;
|
||||||
|
getCommand2MC().addParamConverter(OfflinePlayer.class, Bukkit::getOfflinePlayer, "Player not found!", playerSupplier);
|
||||||
|
getCommand2MC().addParamConverter(Player.class, Bukkit::getPlayer, "Online player not found!", playerSupplier);
|
||||||
|
if (writePluginList.get()) {
|
||||||
try {
|
try {
|
||||||
Files.write(new File("plugins", "plugins.txt").toPath(), Arrays.stream(Bukkit.getPluginManager().getPlugins()).map(p -> (CharSequence) p.getDataFolder().getName())::iterator);
|
Files.write(new File("plugins", "plugins.txt").toPath(), Arrays.stream(Bukkit.getPluginManager().getPlugins()).map(p -> (CharSequence) p.getDataFolder().getName())::iterator);
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
TBMCCoreAPI.SendException("Failed to write plugin list!", e);
|
TBMCCoreAPI.SendException("Failed to write plugin list!", e, this);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ess = Essentials.getPlugin(Essentials.class);
|
if (getServer().getPluginManager().isPluginEnabled("Essentials"))
|
||||||
logger.info(pdf.getName() + " has been Enabled (V." + pdf.getVersion() + ") Test: " + test().get() + ".");
|
ess = Essentials.getPlugin(Essentials.class);
|
||||||
|
logger.info(pdf.getName() + " has been Enabled (V." + pdf.getVersion() + ") Test: " + test.get() + ".");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void pluginDisable() {
|
public void pluginDisable() {
|
||||||
logger.info("Saving player data...");
|
logger.info("Saving player data...");
|
||||||
TBMCPlayerBase.savePlayers();
|
ChromaGamerBase.saveUsers();
|
||||||
logger.info("Player data saved.");
|
logger.info("Player data saved.");
|
||||||
new Thread(() -> {
|
|
||||||
File[] files = PluginUpdater.updatedir.listFiles();
|
|
||||||
if (files == null)
|
|
||||||
return;
|
|
||||||
logger.info("Updating " + files.length + " plugins...");
|
|
||||||
for (File file : files) {
|
|
||||||
try {
|
|
||||||
Files.move(file.toPath(), new File("plugins", file.getName()).toPath(), StandardCopyOption.REPLACE_EXISTING);
|
|
||||||
logger.info("Updated " + file.getName());
|
|
||||||
} catch (IOException e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
logger.info("Update complete!");
|
|
||||||
}).start();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean setupPermissions() {
|
private boolean setupPermissions() {
|
|
@ -5,6 +5,7 @@ import buttondevteam.lib.architecture.ButtonPlugin;
|
||||||
import buttondevteam.lib.chat.ChatMessage;
|
import buttondevteam.lib.chat.ChatMessage;
|
||||||
import buttondevteam.lib.chat.Command2MCSender;
|
import buttondevteam.lib.chat.Command2MCSender;
|
||||||
import buttondevteam.lib.chat.TBMCChatAPI;
|
import buttondevteam.lib.chat.TBMCChatAPI;
|
||||||
|
import buttondevteam.lib.player.ChromaGamerBase;
|
||||||
import buttondevteam.lib.player.TBMCPlayer;
|
import buttondevteam.lib.player.TBMCPlayer;
|
||||||
import buttondevteam.lib.player.TBMCPlayerBase;
|
import buttondevteam.lib.player.TBMCPlayerBase;
|
||||||
import lombok.val;
|
import lombok.val;
|
||||||
|
@ -27,23 +28,32 @@ public class PlayerListener implements Listener {
|
||||||
|
|
||||||
@EventHandler(priority = EventPriority.NORMAL)
|
@EventHandler(priority = EventPriority.NORMAL)
|
||||||
public void OnPlayerJoin(PlayerJoinEvent event) {
|
public void OnPlayerJoin(PlayerJoinEvent event) {
|
||||||
TBMCPlayerBase.joinPlayer(event.getPlayer());
|
var p = event.getPlayer();
|
||||||
|
TBMCPlayer player = TBMCPlayerBase.getPlayer(p.getUniqueId(), TBMCPlayer.class);
|
||||||
|
String pname = player.PlayerName.get();
|
||||||
|
if (pname.length() == 0) {
|
||||||
|
player.PlayerName.set(p.getName());
|
||||||
|
MainPlugin.Instance.getLogger().info("Player name saved: " + player.PlayerName.get());
|
||||||
|
} else if (!p.getName().equals(pname)) {
|
||||||
|
MainPlugin.Instance.getLogger().info(pname + " renamed to " + p.getName());
|
||||||
|
player.PlayerName.set(p.getName());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@EventHandler(priority = EventPriority.NORMAL)
|
@EventHandler(priority = EventPriority.NORMAL)
|
||||||
public void OnPlayerLeave(PlayerQuitEvent event) {
|
public void OnPlayerLeave(PlayerQuitEvent event) {
|
||||||
TBMCPlayerBase.quitPlayer(event.getPlayer());
|
TBMCPlayerBase.getPlayer(event.getPlayer().getUniqueId(), TBMCPlayer.class).uncache();
|
||||||
}
|
}
|
||||||
|
|
||||||
@EventHandler(priority = EventPriority.HIGHEST)
|
@EventHandler(priority = EventPriority.HIGHEST)
|
||||||
public void onSystemChat(TBMCSystemChatEvent event) {
|
public void onSystemChat(TBMCSystemChatEvent event) {
|
||||||
if (event.isHandled())
|
if (event.isHandled())
|
||||||
return; // Only handle here if ButtonChat couldn't - ButtonChat doesn't even handle this
|
return; // Only handle here if ButtonChat couldn't - ButtonChat doesn't even handle this
|
||||||
if (Arrays.stream(event.getExceptions()).anyMatch("Minecraft"::equalsIgnoreCase))
|
if (Arrays.stream(event.getExceptions()).anyMatch("Minecraft"::equalsIgnoreCase))
|
||||||
return;
|
return;
|
||||||
Bukkit.getOnlinePlayers().stream().filter(event::shouldSendTo)
|
Bukkit.getOnlinePlayers().stream().filter(event::shouldSendTo)
|
||||||
.forEach(p -> p.sendMessage(event.getChannel().DisplayName().get().substring(0, 2) + event.getMessage()));
|
.forEach(p -> p.sendMessage(event.getChannel().DisplayName.get().substring(0, 2) + event.getMessage()));
|
||||||
}
|
}
|
||||||
|
|
||||||
@EventHandler
|
@EventHandler
|
||||||
public void onPlayerChatPreprocess(PlayerCommandPreprocessEvent event) {
|
public void onPlayerChatPreprocess(PlayerCommandPreprocessEvent event) {
|
||||||
|
@ -58,7 +68,9 @@ public class PlayerListener implements Listener {
|
||||||
|
|
||||||
private void handlePreprocess(CommandSender sender, String message, Cancellable event) {
|
private void handlePreprocess(CommandSender sender, String message, Cancellable event) {
|
||||||
if (event.isCancelled()) return;
|
if (event.isCancelled()) return;
|
||||||
val ev = new TBMCCommandPreprocessEvent(sender, message);
|
val cg = ChromaGamerBase.getFromSender(sender);
|
||||||
|
if (cg == null) throw new RuntimeException("Couldn't get user from sender for " + sender.getName() + "!");
|
||||||
|
val ev = new TBMCCommandPreprocessEvent(sender, cg.channel.get(), message, sender);
|
||||||
Bukkit.getPluginManager().callEvent(ev);
|
Bukkit.getPluginManager().callEvent(ev);
|
||||||
if (ev.isCancelled())
|
if (ev.isCancelled())
|
||||||
event.setCancelled(true); //Cancel the original event
|
event.setCancelled(true); //Cancel the original event
|
||||||
|
@ -68,9 +80,9 @@ public class PlayerListener implements Listener {
|
||||||
public void onTBMCPreprocess(TBMCCommandPreprocessEvent event) {
|
public void onTBMCPreprocess(TBMCCommandPreprocessEvent event) {
|
||||||
if (event.isCancelled()) return;
|
if (event.isCancelled()) return;
|
||||||
try {
|
try {
|
||||||
event.setCancelled(ButtonPlugin.getCommand2MC().handleCommand(new Command2MCSender(event.getSender()), event.getMessage()));
|
event.setCancelled(ButtonPlugin.getCommand2MC().handleCommand(new Command2MCSender(event.getSender(), event.getChannel(), event.getPermCheck()), event.getMessage()));
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
TBMCCoreAPI.SendException("Command processing failed for sender '" + event.getSender() + "' and message '" + event.getMessage() + "'", e);
|
TBMCCoreAPI.SendException("Command processing failed for sender '" + event.getSender() + "' and message '" + event.getMessage() + "'", e, MainPlugin.Instance);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -90,11 +102,12 @@ public class PlayerListener implements Listener {
|
||||||
return;
|
return;
|
||||||
if (!MainPlugin.Instance.isChatHandlerEnabled()) return;
|
if (!MainPlugin.Instance.isChatHandlerEnabled()) return;
|
||||||
if (event.getOrigin().equals("Minecraft")) return; //Let other plugins handle MC messages
|
if (event.getOrigin().equals("Minecraft")) return; //Let other plugins handle MC messages
|
||||||
String msg = MainPlugin.Instance.chatFormat().get()
|
var channel = event.getChannel();
|
||||||
.replace("{channel}", event.getChannel().DisplayName().get())
|
String msg = MainPlugin.Instance.chatFormat.get()
|
||||||
|
.replace("{channel}", channel.DisplayName.get())
|
||||||
.replace("{origin}", event.getOrigin().substring(0, 1))
|
.replace("{origin}", event.getOrigin().substring(0, 1))
|
||||||
.replace("{name}", ThorpeUtils.getDisplayName(event.getSender()))
|
.replace("{name}", ChromaUtils.getDisplayName(event.getSender()))
|
||||||
.replace("{message}", event.getMessage());
|
.replace("{message}", String.format("§%x%s", channel.Color.get().ordinal(), event.getMessage()));
|
||||||
for (Player player : Bukkit.getOnlinePlayers())
|
for (Player player : Bukkit.getOnlinePlayers())
|
||||||
if (event.shouldSendTo(player))
|
if (event.shouldSendTo(player))
|
||||||
player.sendMessage(msg);
|
player.sendMessage(msg);
|
|
@ -2,6 +2,7 @@ package buttondevteam.core;
|
||||||
|
|
||||||
import buttondevteam.core.component.channel.Channel;
|
import buttondevteam.core.component.channel.Channel;
|
||||||
import buttondevteam.core.component.channel.ChannelComponent;
|
import buttondevteam.core.component.channel.ChannelComponent;
|
||||||
|
import buttondevteam.lib.ChromaUtils;
|
||||||
import buttondevteam.lib.architecture.Component;
|
import buttondevteam.lib.architecture.Component;
|
||||||
import buttondevteam.lib.chat.Color;
|
import buttondevteam.lib.chat.Color;
|
||||||
import buttondevteam.lib.chat.TBMCChatAPI;
|
import buttondevteam.lib.chat.TBMCChatAPI;
|
||||||
|
@ -19,11 +20,13 @@ import java.util.Collections;
|
||||||
import java.util.logging.Logger;
|
import java.util.logging.Logger;
|
||||||
|
|
||||||
public class TestPrepare {
|
public class TestPrepare {
|
||||||
|
|
||||||
public static void PrepareServer() {
|
public static void PrepareServer() {
|
||||||
|
ChromaUtils.setTest(); //Needs to be in a separate class because of the potential lack of Mockito
|
||||||
Bukkit.setServer(Mockito.mock(Server.class, new Answer<Object>() {
|
Bukkit.setServer(Mockito.mock(Server.class, new Answer<Object>() {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Object answer(InvocationOnMock invocation) {
|
public Object answer(InvocationOnMock invocation) {
|
||||||
if (returns(invocation, String.class))
|
if (returns(invocation, String.class))
|
||||||
return "test";
|
return "test";
|
||||||
if (returns(invocation, Logger.class))
|
if (returns(invocation, Logger.class))
|
||||||
|
@ -41,7 +44,6 @@ public class TestPrepare {
|
||||||
return cl.isAssignableFrom(invocation.getMethod().getReturnType());
|
return cl.isAssignableFrom(invocation.getMethod().getReturnType());
|
||||||
}
|
}
|
||||||
}));
|
}));
|
||||||
//noinspection unchecked
|
|
||||||
Component.registerComponent(Mockito.mock(JavaPlugin.class), new ChannelComponent());
|
Component.registerComponent(Mockito.mock(JavaPlugin.class), new ChannelComponent());
|
||||||
TBMCChatAPI.RegisterChatChannel(Channel.GlobalChat = new Channel("§fg§f", Color.White, "g", null));
|
TBMCChatAPI.RegisterChatChannel(Channel.GlobalChat = new Channel("§fg§f", Color.White, "g", null));
|
||||||
}
|
}
|
237
Chroma-Core/src/main/java/buttondevteam/core/component/channel/Channel.java
Executable file
237
Chroma-Core/src/main/java/buttondevteam/core/component/channel/Channel.java
Executable file
|
@ -0,0 +1,237 @@
|
||||||
|
package buttondevteam.core.component.channel;
|
||||||
|
|
||||||
|
import buttondevteam.core.ComponentManager;
|
||||||
|
import buttondevteam.core.MainPlugin;
|
||||||
|
import buttondevteam.lib.architecture.Component;
|
||||||
|
import buttondevteam.lib.architecture.ConfigData;
|
||||||
|
import buttondevteam.lib.architecture.IHaveConfig;
|
||||||
|
import buttondevteam.lib.chat.Color;
|
||||||
|
import com.google.common.collect.Lists;
|
||||||
|
import org.bukkit.Bukkit;
|
||||||
|
import org.bukkit.command.CommandSender;
|
||||||
|
import org.bukkit.entity.Player;
|
||||||
|
|
||||||
|
import javax.annotation.Nullable;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.function.BiFunction;
|
||||||
|
import java.util.function.BiPredicate;
|
||||||
|
import java.util.function.Function;
|
||||||
|
import java.util.function.Predicate;
|
||||||
|
import java.util.stream.Stream;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Represents a chat channel. May only be instantiated after the channel component is registered.
|
||||||
|
*/
|
||||||
|
public class Channel {
|
||||||
|
/**
|
||||||
|
* Specifies a score that means it's OK to send - but it does not define any groups, only send or not send. See {@link #GROUP_EVERYONE}
|
||||||
|
*/
|
||||||
|
public static final int SCORE_SEND_OK = 0;
|
||||||
|
/**
|
||||||
|
* Specifies a score that means the user doesn't have permission to see or send the message. Any negative value has the same effect.
|
||||||
|
*/
|
||||||
|
public static final int SCORE_SEND_NOPE = -1;
|
||||||
|
/**
|
||||||
|
* Send the message to everyone <i>who has access to the channel</i> - this does not necessarily mean all players
|
||||||
|
*/
|
||||||
|
public static final String GROUP_EVERYONE = "everyone";
|
||||||
|
|
||||||
|
private static ChannelComponent component;
|
||||||
|
|
||||||
|
private String defDisplayName;
|
||||||
|
private Color defColor;
|
||||||
|
|
||||||
|
private IHaveConfig config;
|
||||||
|
|
||||||
|
public final ConfigData<Boolean> Enabled;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Must start with a color code
|
||||||
|
*/
|
||||||
|
public final ConfigData<String> DisplayName;
|
||||||
|
|
||||||
|
public final ConfigData<Color> Color;
|
||||||
|
public final String ID;
|
||||||
|
|
||||||
|
public ConfigData<String[]> IDs;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Filters both the sender and the targets
|
||||||
|
*/
|
||||||
|
private final Function<CommandSender, RecipientTestResult> filteranderrormsg;
|
||||||
|
|
||||||
|
private static final List<Channel> channels = new ArrayList<>();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a channel.
|
||||||
|
*
|
||||||
|
* @param displayname The name that should appear at the start of the message. <b>A chat color is expected at the beginning (§9).</b>
|
||||||
|
* @param color The default color of the messages sent in the channel
|
||||||
|
* @param command The command to be used for the channel <i>without /</i>. For example "mod". It's also used for scoreboard objective names.
|
||||||
|
* @param filteranderrormsg Checks all senders against the criteria provided here and sends the message if the index matches the sender's - if no score at all, displays the error.<br>
|
||||||
|
* May be null to send to everyone.
|
||||||
|
*/
|
||||||
|
public Channel(String displayname, Color color, String command,
|
||||||
|
Function<CommandSender, RecipientTestResult> filteranderrormsg) {
|
||||||
|
defDisplayName = displayname;
|
||||||
|
defColor = color;
|
||||||
|
ID = command;
|
||||||
|
this.filteranderrormsg = filteranderrormsg;
|
||||||
|
init();
|
||||||
|
Enabled = component.getConfig().getData(ID + ".enabled", true);
|
||||||
|
DisplayName = component.getConfig().getData(ID + ".displayName", defDisplayName);
|
||||||
|
Color = component.getConfig().getData(ID + ".color", defColor, c -> buttondevteam.lib.chat.Color.valueOf((String) c), Enum::toString);
|
||||||
|
//noinspection unchecked
|
||||||
|
IDs = component.getConfig().getData(ID + ".IDs", new String[0], l -> ((List<String>) l).toArray(new String[0]), Lists::newArrayList);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Must be only called from a subclass - otherwise it'll throw an exception.
|
||||||
|
*
|
||||||
|
* @see Channel#Channel(String, Color, String, Function)
|
||||||
|
*/
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
protected <T extends Channel> Channel(String displayname, Color color, String command,
|
||||||
|
BiFunction<T, CommandSender, RecipientTestResult> filteranderrormsg) {
|
||||||
|
defDisplayName = displayname;
|
||||||
|
defColor = color;
|
||||||
|
ID = command;
|
||||||
|
this.filteranderrormsg = s -> filteranderrormsg.apply((T) this, s);
|
||||||
|
init();
|
||||||
|
Enabled = component.getConfig().getData(ID + ".enabled", true);
|
||||||
|
DisplayName = component.getConfig().getData(ID + ".displayName", defDisplayName);
|
||||||
|
Color = component.getConfig().getData(ID + ".color", defColor, c -> buttondevteam.lib.chat.Color.valueOf((String) c), Enum::toString);
|
||||||
|
//noinspection unchecked
|
||||||
|
IDs = component.getConfig().getData(ID + ".IDs", new String[0], l -> ((List<String>) l).toArray(new String[0]), Lists::newArrayList);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void init() {
|
||||||
|
if (component == null)
|
||||||
|
component = (ChannelComponent) Component.getComponents().get(ChannelComponent.class);
|
||||||
|
if (component == null)
|
||||||
|
throw new RuntimeException("Attempting to create a channel before the component is registered!");
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isGlobal() {
|
||||||
|
return filteranderrormsg == null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Note: Errors are sent to the sender automatically
|
||||||
|
*
|
||||||
|
* @param sender The user we're sending to
|
||||||
|
* @param score The (source) score to compare with the user's
|
||||||
|
*/
|
||||||
|
public boolean shouldSendTo(CommandSender sender, int score) {
|
||||||
|
return score == getMCScore(sender); //If there's any error, the score won't be equal
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Note: Errors are sent to the sender automatically
|
||||||
|
*/
|
||||||
|
public int getMCScore(CommandSender sender) {
|
||||||
|
return getRTR(sender).score; //No need to check if there was an error
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Note: Errors are sent to the sender automatically<br>
|
||||||
|
* <p>
|
||||||
|
* Null means don't send
|
||||||
|
*/
|
||||||
|
@Nullable
|
||||||
|
public String getGroupID(CommandSender sender) {
|
||||||
|
return getRTR(sender).groupID; //No need to check if there was an error
|
||||||
|
}
|
||||||
|
|
||||||
|
public RecipientTestResult getRTR(CommandSender sender) {
|
||||||
|
if (filteranderrormsg == null)
|
||||||
|
return new RecipientTestResult(SCORE_SEND_OK, GROUP_EVERYONE);
|
||||||
|
return filteranderrormsg.apply(sender);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get a stream of the enabled channels
|
||||||
|
*
|
||||||
|
* @return Only the enabled channels
|
||||||
|
*/
|
||||||
|
public static Stream<Channel> getChannels() {
|
||||||
|
return channels.stream().filter(ch -> ch.Enabled.get());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return all channels whether they're enabled or not
|
||||||
|
*
|
||||||
|
* @return A list of all channels
|
||||||
|
*/
|
||||||
|
public static List<Channel> getChannelList() {
|
||||||
|
return Collections.unmodifiableList(channels);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Convenience method for the function parameter of {@link #Channel(String, Color, String, Function)}. It checks if the sender is OP or optionally has the specified group. The error message is
|
||||||
|
* generated automatically.
|
||||||
|
*
|
||||||
|
* @param permgroup The group that can access the channel or <b>null</b> to only allow OPs.
|
||||||
|
* @return If has access
|
||||||
|
*/
|
||||||
|
public static Function<CommandSender, RecipientTestResult> inGroupFilter(String permgroup) {
|
||||||
|
return noScoreResult(
|
||||||
|
s -> s.isOp() || (permgroup != null && (s instanceof Player && MainPlugin.permission != null && MainPlugin.permission.playerInGroup((Player) s, permgroup))),
|
||||||
|
"You need to be a(n) " + (permgroup != null ? permgroup : "OP") + " to use this channel.");
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Function<CommandSender, RecipientTestResult> noScoreResult(Predicate<CommandSender> filter,
|
||||||
|
String errormsg) {
|
||||||
|
return s -> filter.test(s) ? new RecipientTestResult(SCORE_SEND_OK, GROUP_EVERYONE) : new RecipientTestResult(errormsg);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static <T extends Channel> BiFunction<T, CommandSender, RecipientTestResult> noScoreResult(
|
||||||
|
BiPredicate<T, CommandSender> filter, String errormsg) {
|
||||||
|
return (this_, s) -> filter.test(this_, s) ? new RecipientTestResult(SCORE_SEND_OK, GROUP_EVERYONE) : new RecipientTestResult(errormsg);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Channel GlobalChat;
|
||||||
|
public static Channel AdminChat;
|
||||||
|
public static Channel ModChat;
|
||||||
|
|
||||||
|
public static void RegisterChannel(Channel channel) {
|
||||||
|
if (!channel.isGlobal() && !ComponentManager.isEnabled(ChannelComponent.class))
|
||||||
|
return; //Allow registering the global chat (and I guess other chats like the RP chat)
|
||||||
|
channels.add(channel);
|
||||||
|
component.registerChannelCommand(channel);
|
||||||
|
Bukkit.getScheduler().runTask(MainPlugin.Instance, () -> Bukkit.getPluginManager().callEvent(new ChatChannelRegisterEvent(channel))); // Wait for server start
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class RecipientTestResult {
|
||||||
|
public final String errormessage;
|
||||||
|
public final int score; // Anything below 0 is "never send"
|
||||||
|
public final String groupID;
|
||||||
|
public static final RecipientTestResult ALL = new RecipientTestResult(SCORE_SEND_OK, GROUP_EVERYONE);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a result that indicates an <b>error</b>
|
||||||
|
*
|
||||||
|
* @param errormessage The error message to show the sender if they don't meet the criteria.
|
||||||
|
*/
|
||||||
|
public RecipientTestResult(String errormessage) {
|
||||||
|
this.errormessage = errormessage;
|
||||||
|
this.score = SCORE_SEND_NOPE;
|
||||||
|
this.groupID = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a result that indicates a <b>success</b>
|
||||||
|
*
|
||||||
|
* @param score The score that identifies the target group. <b>Must be non-negative.</b> For example, the index of the town or nation to send to.
|
||||||
|
* @param groupID The ID of the target group.
|
||||||
|
*/
|
||||||
|
public RecipientTestResult(int score, String groupID) {
|
||||||
|
if (score < 0) throw new IllegalArgumentException("Score must be non-negative!");
|
||||||
|
this.score = score;
|
||||||
|
this.groupID = groupID;
|
||||||
|
this.errormessage = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,83 @@
|
||||||
|
package buttondevteam.core.component.channel;
|
||||||
|
|
||||||
|
import buttondevteam.lib.ChromaUtils;
|
||||||
|
import buttondevteam.lib.TBMCSystemChatEvent;
|
||||||
|
import buttondevteam.lib.architecture.Component;
|
||||||
|
import buttondevteam.lib.chat.*;
|
||||||
|
import buttondevteam.lib.player.ChromaGamerBase;
|
||||||
|
import lombok.RequiredArgsConstructor;
|
||||||
|
import org.bukkit.plugin.java.JavaPlugin;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Manages chat channels. If disabled, only global channels will be registered.
|
||||||
|
*/
|
||||||
|
public class ChannelComponent extends Component<JavaPlugin> {
|
||||||
|
static TBMCSystemChatEvent.BroadcastTarget roomJoinLeave;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void register(JavaPlugin plugin) {
|
||||||
|
super.register(plugin);
|
||||||
|
roomJoinLeave = TBMCSystemChatEvent.BroadcastTarget.add("roomJoinLeave"); //Even if it's disabled, global channels continue to work
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void unregister(JavaPlugin plugin) {
|
||||||
|
super.unregister(plugin);
|
||||||
|
TBMCSystemChatEvent.BroadcastTarget.remove(roomJoinLeave);
|
||||||
|
roomJoinLeave = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void enable() {
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void disable() {
|
||||||
|
}
|
||||||
|
|
||||||
|
void registerChannelCommand(Channel channel) {
|
||||||
|
if (!ChromaUtils.isTest())
|
||||||
|
registerCommand(new ChannelCommand(channel));
|
||||||
|
}
|
||||||
|
|
||||||
|
@CommandClass
|
||||||
|
@RequiredArgsConstructor
|
||||||
|
private static class ChannelCommand extends ICommand2MC {
|
||||||
|
private final Channel channel;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getCommandPath() {
|
||||||
|
return channel.ID;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String[] getCommandPaths() {
|
||||||
|
return channel.IDs.get();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Command2.Subcommand
|
||||||
|
public void def(Command2MCSender senderMC, @Command2.OptionalArg @Command2.TextArg String message) {
|
||||||
|
var sender = senderMC.getSender();
|
||||||
|
var user = ChromaGamerBase.getFromSender(sender);
|
||||||
|
if (user == null) {
|
||||||
|
sender.sendMessage("§cYou can't use channels from this platform.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (message == null) {
|
||||||
|
Channel oldch = user.channel.get();
|
||||||
|
if (oldch instanceof ChatRoom)
|
||||||
|
((ChatRoom) oldch).leaveRoom(sender);
|
||||||
|
if (oldch.equals(channel))
|
||||||
|
user.channel.set(Channel.GlobalChat);
|
||||||
|
else {
|
||||||
|
user.channel.set(channel);
|
||||||
|
if (channel instanceof ChatRoom)
|
||||||
|
((ChatRoom) channel).joinRoom(sender);
|
||||||
|
}
|
||||||
|
sender.sendMessage("§6You are now talking in: §b" + user.channel.get().DisplayName.get());
|
||||||
|
} else
|
||||||
|
TBMCChatAPI.SendChatMessage(ChatMessage.builder(sender, user, message).fromCommand(true)
|
||||||
|
.permCheck(senderMC.getPermCheck()).build(), channel);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue