mirror of
https://github.com/GeyserMC/Floodgate.git
synced 2025-12-19 14:59:20 +00:00
Merge pull request #397 from GeyserMC/development
* Started using plugin messages internally. Started subcommand refactor * Removed config holder and changed a few things * Small changes to platforms and injectors * Changed how post-enable messages work internally + minor other changes * Deprecate handshake handlers and player properties * Added auto-binding * Switched event library * Fixed a circular dependency issue when a locale couldn't be found * Simplified plugin message channel logic * Switched to Hikari for MySQL * SkinApplier now only applies a skin if a player doesn't already have one (#330) * SkinApplier now only applies a skin if a player doesn't already have one * add `hasSkin` method to SkinApplier and check for exising skins before overwriting * remove the use of Streams and Optionals * correct delay in SpigotSkinApplier to use ticks instead of milliseconds * Minor changes Co-authored-by: Tim203 <mctim203@gmail.com> * Updated to the latest events version. Share a thread pool * News needs a scheduled executor * Bumped version to 2.1.1 and publish entire java component * Fix checking for existing skins on Spigot (#362) * Close all skin sockets on shutdown (#363) * Only apply skin when someone doesn't have a skin applied already (#365) Instead of aplying only when the player has a skin apply only when it doesn't have a skin * Use UTF-8 for language files (#366) Languages like ru_RU don't work because they have specific characters, and your files are encoded in UTF-8, but it reads them as ISO 8859-1 * Fixed building Floodgate and added a version subcommand * Remove Blossom and use templates * Use weak references for injected Netty channels * Use newSetFromMap * Added a SkinApplyEvent that can cancel/edit the to be applied skin * Use a common ScheduledThreadPool and make the player map concurrent * Don't try to remove all injector references * Add branch name when not master, simplify publish, use GitHub Actions And updated Gradle * Remove Jenkinsfile * Retrieve version from gradle.properties * Let's see if the setup-java action's cache is helpful & fixed building * Add publishing to downloads site (#385) * Add publishing to downloads site * Only publish to Downloads API when branch is master and status success --------- Co-authored-by: Tim203 <mctim203@gmail.com> * Notify Discord after building & fixed building * Temporarily restore Jenkinsfile to give people time to switch * Localize floodgate.core.not_linked (#383) * Localize floodgate.core.not_linked * Update languages submodule * not_linked string has changed slightly --------- Co-authored-by: Tim203 <mctim203@gmail.com> * Update bstats dependency * Only publish and notify Discord on push if running inside this repository (#387) * Only attempt publishing if running in GeyserMC/Floodgate * Also restrict the discord notification * Fix injection of LanguageManager/Slf4jFloodgate on Velocity (circular proxy) (#388) * Made various changes to the build action * Update maven deploy location * Relocate MySQL database extension dependencies * Shutdown metrics on platform shutdown (#386) * Shutdown metrics on platorm shutdown * Listen to event instead of hardcoding it * Annotate Metrics as a Listener * Use temporary bStats fork to properly shutdown bStats * Use bstats-base dependency (instead of the whole project I guess?) * Formatting change --------- Co-authored-by: Tim203 <mctim203@gmail.com> --------- Co-authored-by: Alex <me@teamplayer.io> Co-authored-by: Konicai <71294714+Konicai@users.noreply.github.com> Co-authored-by: mastermc05 <63639746+mastermc05@users.noreply.github.com> Co-authored-by: rtm516 <rtm516@users.noreply.github.com>
This commit is contained in:
63
.github/workflows/build.yml
vendored
Normal file
63
.github/workflows/build.yml
vendored
Normal file
@@ -0,0 +1,63 @@
|
|||||||
|
name: Build
|
||||||
|
|
||||||
|
on: [push]
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
build:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- name: Checkout repository and submodules
|
||||||
|
uses: actions/checkout@v3
|
||||||
|
with:
|
||||||
|
submodules: recursive
|
||||||
|
|
||||||
|
- uses: actions/setup-java@v3
|
||||||
|
with:
|
||||||
|
java-version: 8
|
||||||
|
distribution: temurin
|
||||||
|
|
||||||
|
- name: Build
|
||||||
|
uses: gradle/gradle-build-action@v2
|
||||||
|
with:
|
||||||
|
arguments: build
|
||||||
|
cache-read-only: ${{ github.ref_name != 'master' && github.ref_name != 'development' }}
|
||||||
|
|
||||||
|
- name: Publish to Maven Repository
|
||||||
|
if: ${{ github.repository == 'GeyserMC/Floodgate' }}
|
||||||
|
uses: gradle/gradle-build-action@v2
|
||||||
|
env:
|
||||||
|
ORG_GRADLE_PROJECT_geysermcUsername: ${{ vars.DEPLOY_USER }}
|
||||||
|
ORG_GRADLE_PROJECT_geysermcPassword: ${{ secrets.DEPLOY_PASS }}
|
||||||
|
with:
|
||||||
|
arguments: publish
|
||||||
|
cache-read-only: ${{ github.ref_name != 'master' && github.ref_name != 'development' }}
|
||||||
|
|
||||||
|
- name: Publish to Downloads API
|
||||||
|
if: ${{ github.ref_name == 'master' && github.repository == 'GeyserMC/Floodgate' }}
|
||||||
|
shell: bash
|
||||||
|
env:
|
||||||
|
DOWNLOADS_USERNAME: ${{ vars.DOWNLOADS_USERNAME }}
|
||||||
|
DOWNLOADS_PRIVATE_KEY: ${{ secrets.DOWNLOADS_PRIVATE_KEY }}
|
||||||
|
DOWNLOADS_SERVER_IP: ${{ secrets.DOWNLOADS_SERVER_IP }}
|
||||||
|
run: |
|
||||||
|
# Save the private key to a file
|
||||||
|
echo "$DOWNLOADS_PRIVATE_KEY" > id_ecdsa
|
||||||
|
chmod 600 id_ecdsa
|
||||||
|
|
||||||
|
# Get the version from gradle.properties
|
||||||
|
version=$(cat gradle.properties | grep -o "version=[0-9\\.]*" | cut -d"=" -f2)
|
||||||
|
|
||||||
|
# Copy over artifacts
|
||||||
|
scp -B -o StrictHostKeyChecking=no -i id_ecdsa **/build/libs/floodgate-*.jar $DOWNLOADS_USERNAME@$DOWNLOADS_SERVER_IP:~/files/
|
||||||
|
|
||||||
|
# Remove un-needed artifacts
|
||||||
|
ssh -o StrictHostKeyChecking=no -i id_ecdsa $DOWNLOADS_USERNAME@$DOWNLOADS_SERVER_IP rm ~/files/floodgate-parent-*.jar ~/files/floodgate-api.jar ~/files/floodgate-core.jar
|
||||||
|
|
||||||
|
# Run the build script
|
||||||
|
ssh -o StrictHostKeyChecking=no -i id_ecdsa $DOWNLOADS_USERNAME@$DOWNLOADS_SERVER_IP ./handleBuild.sh floodgate $version $GITHUB_RUN_NUMBER $GITHUB_SHA
|
||||||
|
|
||||||
|
- name: Notify Discord
|
||||||
|
if: ${{ (success() || failure()) && github.repository == 'GeyserMC/Floodgate' }}
|
||||||
|
uses: Tim203/actions-git-discord-webhook@main
|
||||||
|
with:
|
||||||
|
webhook_url: ${{ secrets.DISCORD_WEBHOOK }}
|
||||||
97
.gitignore
vendored
97
.gitignore
vendored
@@ -1,5 +1,5 @@
|
|||||||
# Created by https://www.gitignore.io/api/git,java,maven,eclipse,netbeans,jetbrains+all
|
# Created by https://www.gitignore.io/api/git,java,gradle,eclipse,netbeans,jetbrains+all
|
||||||
# Edit at https://www.gitignore.io/?templates=git,java,maven,eclipse,netbeans,jetbrains+all
|
# Edit at https://www.gitignore.io/?templates=git,gradle,maven,eclipse,netbeans,jetbrains+all
|
||||||
|
|
||||||
### Eclipse ###
|
### Eclipse ###
|
||||||
.metadata
|
.metadata
|
||||||
@@ -52,22 +52,19 @@ local.properties
|
|||||||
|
|
||||||
# Annotation Processing
|
# Annotation Processing
|
||||||
.apt_generated/
|
.apt_generated/
|
||||||
|
.apt_generated_test/
|
||||||
|
|
||||||
# Scala IDE specific (Scala & Java development for Eclipse)
|
# Scala IDE specific (Scala & Java development for Eclipse)
|
||||||
.cache-main
|
.cache-main
|
||||||
.scala_dependencies
|
.scala_dependencies
|
||||||
.worksheet
|
.worksheet
|
||||||
|
|
||||||
|
# Uncomment this line if you wish to ignore the project description file.
|
||||||
|
# Typically, this file would be tracked if it contains build/dependency configurations:
|
||||||
|
#.project
|
||||||
|
|
||||||
### Eclipse Patch ###
|
### Eclipse Patch ###
|
||||||
# Eclipse Core
|
# Spring Boot Tooling
|
||||||
.project
|
|
||||||
|
|
||||||
# JDT-specific (Eclipse Java Development Tools)
|
|
||||||
.classpath
|
|
||||||
|
|
||||||
# Annotation Processing
|
|
||||||
.apt_generated
|
|
||||||
|
|
||||||
.sts4-cache/
|
.sts4-cache/
|
||||||
|
|
||||||
### Git ###
|
### Git ###
|
||||||
@@ -109,9 +106,10 @@ local.properties
|
|||||||
|
|
||||||
# virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml
|
# virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml
|
||||||
hs_err_pid*
|
hs_err_pid*
|
||||||
|
replay_pid*
|
||||||
|
|
||||||
### JetBrains+all ###
|
### JetBrains+all ###
|
||||||
# Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio and WebStorm
|
# Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio, WebStorm and Rider
|
||||||
# Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839
|
# Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839
|
||||||
|
|
||||||
# User-specific stuff
|
# User-specific stuff
|
||||||
@@ -121,6 +119,9 @@ hs_err_pid*
|
|||||||
.idea/**/dictionaries
|
.idea/**/dictionaries
|
||||||
.idea/**/shelf
|
.idea/**/shelf
|
||||||
|
|
||||||
|
# AWS User-specific
|
||||||
|
.idea/**/aws.xml
|
||||||
|
|
||||||
# Generated files
|
# Generated files
|
||||||
.idea/**/contentModel.xml
|
.idea/**/contentModel.xml
|
||||||
|
|
||||||
@@ -141,11 +142,14 @@ hs_err_pid*
|
|||||||
# When using Gradle or Maven with auto-import, you should exclude module files,
|
# When using Gradle or Maven with auto-import, you should exclude module files,
|
||||||
# since they will be recreated, and may cause churn. Uncomment if using
|
# since they will be recreated, and may cause churn. Uncomment if using
|
||||||
# auto-import.
|
# auto-import.
|
||||||
# .idea/modules.xml
|
.idea/artifacts
|
||||||
# .idea/*.iml
|
.idea/compiler.xml
|
||||||
# .idea/modules
|
.idea/jarRepositories.xml
|
||||||
# *.iml
|
.idea/modules.xml
|
||||||
# *.ipr
|
.idea/*.iml
|
||||||
|
.idea/modules
|
||||||
|
*.iml
|
||||||
|
*.ipr
|
||||||
|
|
||||||
# CMake
|
# CMake
|
||||||
cmake-build-*/
|
cmake-build-*/
|
||||||
@@ -168,6 +172,9 @@ atlassian-ide-plugin.xml
|
|||||||
# Cursive Clojure plugin
|
# Cursive Clojure plugin
|
||||||
.idea/replstate.xml
|
.idea/replstate.xml
|
||||||
|
|
||||||
|
# SonarLint plugin
|
||||||
|
.idea/sonarlint/
|
||||||
|
|
||||||
# Crashlytics plugin (for Android Studio and IntelliJ)
|
# Crashlytics plugin (for Android Studio and IntelliJ)
|
||||||
com_crashlytics_export_strings.xml
|
com_crashlytics_export_strings.xml
|
||||||
crashlytics.properties
|
crashlytics.properties
|
||||||
@@ -181,32 +188,13 @@ fabric.properties
|
|||||||
.idea/caches/build_file_checksums.ser
|
.idea/caches/build_file_checksums.ser
|
||||||
|
|
||||||
### JetBrains+all Patch ###
|
### JetBrains+all Patch ###
|
||||||
# Ignores the whole .idea folder and all .iml files
|
# Ignore everything but code style settings and run configurations
|
||||||
# See https://github.com/joeblau/gitignore.io/issues/186 and https://github.com/joeblau/gitignore.io/issues/360
|
# that are supposed to be shared within teams.
|
||||||
|
|
||||||
.idea/
|
.idea/*
|
||||||
|
|
||||||
# Reason: https://github.com/joeblau/gitignore.io/issues/186#issuecomment-249601023
|
!.idea/codeStyles
|
||||||
|
!.idea/runConfigurations
|
||||||
*.iml
|
|
||||||
modules.xml
|
|
||||||
.idea/misc.xml
|
|
||||||
*.ipr
|
|
||||||
|
|
||||||
# Sonarlint plugin
|
|
||||||
.idea/sonarlint
|
|
||||||
|
|
||||||
### Maven ###
|
|
||||||
target/
|
|
||||||
pom.xml.tag
|
|
||||||
pom.xml.releaseBackup
|
|
||||||
pom.xml.versionsBackup
|
|
||||||
pom.xml.next
|
|
||||||
release.properties
|
|
||||||
dependency-reduced-pom.xml
|
|
||||||
buildNumber.properties
|
|
||||||
.mvn/timing.properties
|
|
||||||
.mvn/wrapper/maven-wrapper.jar
|
|
||||||
|
|
||||||
### NetBeans ###
|
### NetBeans ###
|
||||||
**/nbproject/private/
|
**/nbproject/private/
|
||||||
@@ -218,8 +206,29 @@ dist/
|
|||||||
nbdist/
|
nbdist/
|
||||||
.nb-gradle/
|
.nb-gradle/
|
||||||
|
|
||||||
# End of https://www.gitignore.io/api/git,java,maven,eclipse,netbeans,jetbrains+all
|
### Gradle ###
|
||||||
gradle/
|
.gradle
|
||||||
**/.gradle/
|
**/build/
|
||||||
|
!src/**/build/
|
||||||
|
|
||||||
|
# Ignore Gradle GUI config
|
||||||
|
gradle-app.setting
|
||||||
|
|
||||||
|
# Avoid ignoring Gradle wrapper jar file (.jar files are usually ignored)
|
||||||
|
!gradle-wrapper.jar
|
||||||
|
|
||||||
|
# Avoid ignore Gradle wrappper properties
|
||||||
|
!gradle-wrapper.properties
|
||||||
|
|
||||||
|
# Cache of project
|
||||||
|
.gradletasknamecache
|
||||||
|
|
||||||
|
# Eclipse Gradle plugin generated files
|
||||||
|
# Eclipse Core
|
||||||
|
.project
|
||||||
|
# JDT-specific (Eclipse Java Development Tools)
|
||||||
|
.classpath
|
||||||
|
|
||||||
|
# End of https://www.gitignore.io/api/git,java,gradle,eclipse,netbeans,jetbrains+all
|
||||||
|
|
||||||
/core/src/main/resources/languages/
|
/core/src/main/resources/languages/
|
||||||
|
|||||||
82
Jenkinsfile
vendored
82
Jenkinsfile
vendored
@@ -26,87 +26,5 @@ pipeline {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
stage ('Deploy') {
|
|
||||||
when {
|
|
||||||
anyOf {
|
|
||||||
branch "master"
|
|
||||||
branch "development"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
steps {
|
|
||||||
rtGradleDeployer(
|
|
||||||
id: "GRADLE_DEPLOYER",
|
|
||||||
serverId: "opencollab-artifactory",
|
|
||||||
releaseRepo: "maven-releases",
|
|
||||||
snapshotRepo: "maven-snapshots"
|
|
||||||
)
|
|
||||||
rtGradleResolver(
|
|
||||||
id: "GRADLE_RESOLVER",
|
|
||||||
serverId: "opencollab-artifactory"
|
|
||||||
)
|
|
||||||
rtGradleRun(
|
|
||||||
usesPlugin: true,
|
|
||||||
tool: 'Gradle 7',
|
|
||||||
rootDir: "",
|
|
||||||
useWrapper: true,
|
|
||||||
buildFile: 'build.gradle.kts',
|
|
||||||
tasks: 'artifactoryPublish',
|
|
||||||
deployerId: "GRADLE_DEPLOYER",
|
|
||||||
resolverId: "GRADLE_RESOLVER"
|
|
||||||
)
|
|
||||||
rtPublishBuildInfo(
|
|
||||||
serverId: "opencollab-artifactory"
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
post {
|
|
||||||
always {
|
|
||||||
script {
|
|
||||||
def changeLogSets = currentBuild.changeSets
|
|
||||||
def message = "**Changes:**"
|
|
||||||
|
|
||||||
if (changeLogSets.size() == 0) {
|
|
||||||
message += "\n*No changes.*"
|
|
||||||
} else {
|
|
||||||
def repositoryUrl = scm.userRemoteConfigs[0].url.replace(".git", "")
|
|
||||||
def count = 0;
|
|
||||||
def extra = 0;
|
|
||||||
for (int i = 0; i < changeLogSets.size(); i++) {
|
|
||||||
def entries = changeLogSets[i].items
|
|
||||||
for (int j = 0; j < entries.length; j++) {
|
|
||||||
if (count <= 10) {
|
|
||||||
def entry = entries[j]
|
|
||||||
def commitId = entry.commitId.substring(0, 6)
|
|
||||||
message += "\n - [`${commitId}`](${repositoryUrl}/commit/${entry.commitId}) ${entry.msg}"
|
|
||||||
count++
|
|
||||||
} else {
|
|
||||||
extra++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (extra != 0) {
|
|
||||||
message += "\n - ${extra} more commits"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
env.changes = message
|
|
||||||
}
|
|
||||||
deleteDir()
|
|
||||||
withCredentials([string(credentialsId: 'geyser-discord-webhook', variable: 'DISCORD_WEBHOOK')]) {
|
|
||||||
discordSend description: "**Build:** [${currentBuild.id}](${env.BUILD_URL})\n**Status:** [${currentBuild.currentResult}](${env.BUILD_URL})\n${changes}\n\n[**Artifacts on Jenkins**](https://ci.opencollab.dev/job/GeyserMC/job/Floodgate)", footer: 'Open Collaboration Jenkins', link: env.BUILD_URL, successful: currentBuild.resultIsBetterOrEqualTo('SUCCESS'), title: "${env.JOB_NAME} #${currentBuild.id}", webhookURL: DISCORD_WEBHOOK
|
|
||||||
}
|
|
||||||
}
|
|
||||||
success {
|
|
||||||
script {
|
|
||||||
if (env.BRANCH_NAME == 'master') {
|
|
||||||
build propagate: false, wait: false, job: 'GeyserMC/Floodgate-Fabric/master', parameters: [booleanParam(name: 'SKIP_DISCORD', value: true)]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
0
ap/build.gradle.kts
Normal file
0
ap/build.gradle.kts
Normal file
@@ -23,37 +23,16 @@
|
|||||||
* @link https://github.com/GeyserMC/Floodgate
|
* @link https://github.com/GeyserMC/Floodgate
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package org.geysermc.floodgate.config;
|
package org.geysermc.floodgate.ap;
|
||||||
|
|
||||||
import org.geysermc.floodgate.util.FloodgateInfoHolder;
|
import javax.annotation.processing.SupportedAnnotationTypes;
|
||||||
|
import javax.annotation.processing.SupportedSourceVersion;
|
||||||
|
import javax.lang.model.SourceVersion;
|
||||||
|
|
||||||
public class FloodgateConfigHolder {
|
@SupportedAnnotationTypes("*")
|
||||||
private FloodgateConfig config;
|
@SupportedSourceVersion(SourceVersion.RELEASE_8)
|
||||||
|
public class AutoBindProcessor extends ClassProcessor {
|
||||||
public boolean has() {
|
public AutoBindProcessor() {
|
||||||
return config != null;
|
super("org.geysermc.floodgate.util.AutoBind");
|
||||||
}
|
|
||||||
|
|
||||||
public boolean isProxy() {
|
|
||||||
return config instanceof ProxyFloodgateConfig;
|
|
||||||
}
|
|
||||||
|
|
||||||
public FloodgateConfig get() {
|
|
||||||
return config;
|
|
||||||
}
|
|
||||||
|
|
||||||
public ProxyFloodgateConfig getAsProxy() {
|
|
||||||
return getAs();
|
|
||||||
}
|
|
||||||
|
|
||||||
@SuppressWarnings("unchecked")
|
|
||||||
public <T extends FloodgateConfig> T getAs() {
|
|
||||||
return (T) config;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void set(FloodgateConfig config) {
|
|
||||||
this.config = config;
|
|
||||||
// for Geyser dump
|
|
||||||
FloodgateInfoHolder.setConfig(config);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
221
ap/src/main/java/org/geysermc/floodgate/ap/ClassProcessor.java
Normal file
221
ap/src/main/java/org/geysermc/floodgate/ap/ClassProcessor.java
Normal file
@@ -0,0 +1,221 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2019-2022 GeyserMC. http://geysermc.org
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
* of this software and associated documentation files (the "Software"), to deal
|
||||||
|
* in the Software without restriction, including without limitation the rights
|
||||||
|
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
* copies of the Software, and to permit persons to whom the Software is
|
||||||
|
* furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in
|
||||||
|
* all copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
|
* THE SOFTWARE.
|
||||||
|
*
|
||||||
|
* @author GeyserMC
|
||||||
|
* @link https://github.com/GeyserMC/Floodgate
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.geysermc.floodgate.ap;
|
||||||
|
|
||||||
|
import java.io.BufferedReader;
|
||||||
|
import java.io.BufferedWriter;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.nio.file.Files;
|
||||||
|
import java.nio.file.NoSuchFileException;
|
||||||
|
import java.nio.file.Path;
|
||||||
|
import java.nio.file.Paths;
|
||||||
|
import java.util.Collection;
|
||||||
|
import java.util.HashSet;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Set;
|
||||||
|
import javax.annotation.processing.AbstractProcessor;
|
||||||
|
import javax.annotation.processing.ProcessingEnvironment;
|
||||||
|
import javax.annotation.processing.RoundEnvironment;
|
||||||
|
import javax.lang.model.element.AnnotationMirror;
|
||||||
|
import javax.lang.model.element.Element;
|
||||||
|
import javax.lang.model.element.ElementKind;
|
||||||
|
import javax.lang.model.element.TypeElement;
|
||||||
|
import javax.tools.Diagnostic.Kind;
|
||||||
|
import javax.tools.FileObject;
|
||||||
|
import javax.tools.StandardLocation;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Copied from Geyser
|
||||||
|
*/
|
||||||
|
public class ClassProcessor extends AbstractProcessor {
|
||||||
|
private final String annotationClassName;
|
||||||
|
|
||||||
|
private Path outputPath;
|
||||||
|
|
||||||
|
private final Set<String> locations = new HashSet<>();
|
||||||
|
|
||||||
|
public ClassProcessor(String annotationClassName) {
|
||||||
|
this.annotationClassName = annotationClassName;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public synchronized void init(ProcessingEnvironment processingEnv) {
|
||||||
|
super.init(processingEnv);
|
||||||
|
|
||||||
|
processingEnv.getMessager().printMessage(
|
||||||
|
Kind.NOTE, "Initializing processor " + annotationClassName
|
||||||
|
);
|
||||||
|
|
||||||
|
String outputFile = processingEnv.getOptions().get("metadataOutputFile");
|
||||||
|
if (outputFile != null && !outputFile.isEmpty()) {
|
||||||
|
outputPath = Paths.get(outputFile);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) {
|
||||||
|
if (roundEnv.processingOver()) {
|
||||||
|
if (!roundEnv.errorRaised()) {
|
||||||
|
complete();
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!contains(annotations, annotationClassName)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (Element element : roundEnv.getRootElements()) {
|
||||||
|
if (element.getKind() != ElementKind.CLASS) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!contains(element.getAnnotationMirrors(), annotationClassName)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
TypeElement typeElement = (TypeElement) element;
|
||||||
|
locations.add(typeElement.getQualifiedName().toString());
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean contains(Collection<? extends TypeElement> elements, String className) {
|
||||||
|
if (elements.isEmpty()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (TypeElement element : elements) {
|
||||||
|
if (element.getQualifiedName().contentEquals(className)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean contains(List<? extends AnnotationMirror> elements, String className) {
|
||||||
|
if (elements.isEmpty()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (AnnotationMirror element : elements) {
|
||||||
|
if (element.getAnnotationType().toString().equals(className)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void complete() {
|
||||||
|
// Read existing annotation list and verify each class still has this annotation
|
||||||
|
try (BufferedReader reader = createReader()) {
|
||||||
|
if (reader != null) {
|
||||||
|
reader.lines().forEach(canonicalName -> {
|
||||||
|
if (!locations.contains(canonicalName)) {
|
||||||
|
|
||||||
|
TypeElement element =
|
||||||
|
processingEnv.getElementUtils().getTypeElement(canonicalName);
|
||||||
|
|
||||||
|
if (element != null && element.getKind() == ElementKind.CLASS &&
|
||||||
|
contains(element.getAnnotationMirrors(), annotationClassName)) {
|
||||||
|
locations.add(canonicalName);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
} catch (IOException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!locations.isEmpty()) {
|
||||||
|
try (BufferedWriter writer = createWriter()) {
|
||||||
|
for (String location : locations) {
|
||||||
|
writer.write(location);
|
||||||
|
writer.newLine();
|
||||||
|
}
|
||||||
|
} catch (IOException ex) {
|
||||||
|
ex.printStackTrace();
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
processingEnv.getMessager().printMessage(Kind.NOTE,
|
||||||
|
"Did not find any classes annotated with " + annotationClassName
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
processingEnv.getMessager().printMessage(
|
||||||
|
Kind.NOTE, "Completed processing for " + annotationClassName
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
private BufferedReader createReader() throws IOException {
|
||||||
|
if (outputPath != null) {
|
||||||
|
processingEnv.getMessager().printMessage(Kind.NOTE,
|
||||||
|
"Reading existing " + annotationClassName + " list from " + outputPath
|
||||||
|
);
|
||||||
|
|
||||||
|
return Files.newBufferedReader(outputPath);
|
||||||
|
}
|
||||||
|
|
||||||
|
FileObject obj = processingEnv.getFiler().getResource(
|
||||||
|
StandardLocation.CLASS_OUTPUT, "", annotationClassName
|
||||||
|
);
|
||||||
|
|
||||||
|
if (obj != null) {
|
||||||
|
processingEnv.getMessager().printMessage(
|
||||||
|
Kind.NOTE,
|
||||||
|
"Reading existing " + annotationClassName + " list from " + obj.toUri()
|
||||||
|
);
|
||||||
|
|
||||||
|
try {
|
||||||
|
return new BufferedReader(obj.openReader(false));
|
||||||
|
} catch (NoSuchFileException ignored) {}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
private BufferedWriter createWriter() throws IOException {
|
||||||
|
if (outputPath != null) {
|
||||||
|
processingEnv.getMessager().printMessage(
|
||||||
|
Kind.NOTE, "Writing " + annotationClassName + " to " + outputPath
|
||||||
|
);
|
||||||
|
|
||||||
|
return Files.newBufferedWriter(outputPath);
|
||||||
|
}
|
||||||
|
|
||||||
|
FileObject obj = processingEnv.getFiler().createResource(
|
||||||
|
StandardLocation.CLASS_OUTPUT, "", annotationClassName
|
||||||
|
);
|
||||||
|
|
||||||
|
processingEnv.getMessager().printMessage(
|
||||||
|
Kind.NOTE, "Writing " + annotationClassName + " to " + obj.toUri()
|
||||||
|
);
|
||||||
|
|
||||||
|
return new BufferedWriter(obj.openWriter());
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
org.geysermc.floodgate.ap.AutoBindProcessor
|
||||||
@@ -1,6 +1,7 @@
|
|||||||
dependencies {
|
dependencies {
|
||||||
api("org.geysermc", "common", Versions.geyserVersion)
|
api("org.geysermc", "common", Versions.geyserVersion)
|
||||||
api("org.geysermc.cumulus", "cumulus", Versions.cumulusVersion)
|
api("org.geysermc.cumulus", "cumulus", Versions.cumulusVersion)
|
||||||
|
api("org.geysermc.event", "events", Versions.eventsVersion)
|
||||||
|
|
||||||
compileOnly("io.netty", "netty-transport", Versions.nettyVersion)
|
compileOnly("io.netty", "netty-transport", Versions.nettyVersion)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -30,6 +30,7 @@ import java.util.UUID;
|
|||||||
import java.util.concurrent.CompletableFuture;
|
import java.util.concurrent.CompletableFuture;
|
||||||
import org.geysermc.cumulus.form.Form;
|
import org.geysermc.cumulus.form.Form;
|
||||||
import org.geysermc.cumulus.form.util.FormBuilder;
|
import org.geysermc.cumulus.form.util.FormBuilder;
|
||||||
|
import org.geysermc.floodgate.api.event.FloodgateEventBus;
|
||||||
import org.geysermc.floodgate.api.link.PlayerLink;
|
import org.geysermc.floodgate.api.link.PlayerLink;
|
||||||
import org.geysermc.floodgate.api.player.FloodgatePlayer;
|
import org.geysermc.floodgate.api.player.FloodgatePlayer;
|
||||||
import org.geysermc.floodgate.api.unsafe.Unsafe;
|
import org.geysermc.floodgate.api.unsafe.Unsafe;
|
||||||
@@ -148,6 +149,10 @@ public interface FloodgateApi {
|
|||||||
*/
|
*/
|
||||||
CompletableFuture<String> getGamertagFor(long xuid);
|
CompletableFuture<String> getGamertagFor(long xuid);
|
||||||
|
|
||||||
|
default FloodgateEventBus getEventBus() {
|
||||||
|
return InstanceHolder.getEventBus();
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the instance that manages all the linking.
|
* Returns the instance that manages all the linking.
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -27,6 +27,7 @@ package org.geysermc.floodgate.api;
|
|||||||
|
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
import lombok.Getter;
|
import lombok.Getter;
|
||||||
|
import org.geysermc.floodgate.api.event.FloodgateEventBus;
|
||||||
import org.geysermc.floodgate.api.handshake.HandshakeHandlers;
|
import org.geysermc.floodgate.api.handshake.HandshakeHandlers;
|
||||||
import org.geysermc.floodgate.api.inject.PlatformInjector;
|
import org.geysermc.floodgate.api.inject.PlatformInjector;
|
||||||
import org.geysermc.floodgate.api.link.PlayerLink;
|
import org.geysermc.floodgate.api.link.PlayerLink;
|
||||||
@@ -35,6 +36,7 @@ import org.geysermc.floodgate.api.packet.PacketHandlers;
|
|||||||
public final class InstanceHolder {
|
public final class InstanceHolder {
|
||||||
@Getter private static FloodgateApi api;
|
@Getter private static FloodgateApi api;
|
||||||
@Getter private static PlayerLink playerLink;
|
@Getter private static PlayerLink playerLink;
|
||||||
|
@Getter private static FloodgateEventBus eventBus;
|
||||||
|
|
||||||
@Getter private static PlatformInjector injector;
|
@Getter private static PlatformInjector injector;
|
||||||
@Getter private static PacketHandlers packetHandlers;
|
@Getter private static PacketHandlers packetHandlers;
|
||||||
@@ -44,11 +46,12 @@ public final class InstanceHolder {
|
|||||||
public static boolean set(
|
public static boolean set(
|
||||||
FloodgateApi floodgateApi,
|
FloodgateApi floodgateApi,
|
||||||
PlayerLink link,
|
PlayerLink link,
|
||||||
|
FloodgateEventBus floodgateEventBus,
|
||||||
PlatformInjector platformInjector,
|
PlatformInjector platformInjector,
|
||||||
PacketHandlers packetHandlers,
|
PacketHandlers packetHandlers,
|
||||||
HandshakeHandlers handshakeHandlers,
|
HandshakeHandlers handshakeHandlers,
|
||||||
UUID key) {
|
UUID key
|
||||||
|
) {
|
||||||
if (storedKey != null) {
|
if (storedKey != null) {
|
||||||
if (!storedKey.equals(key)) {
|
if (!storedKey.equals(key)) {
|
||||||
return false;
|
return false;
|
||||||
@@ -59,14 +62,10 @@ public final class InstanceHolder {
|
|||||||
|
|
||||||
api = floodgateApi;
|
api = floodgateApi;
|
||||||
playerLink = link;
|
playerLink = link;
|
||||||
|
eventBus = floodgateEventBus;
|
||||||
injector = platformInjector;
|
injector = platformInjector;
|
||||||
InstanceHolder.packetHandlers = packetHandlers;
|
InstanceHolder.packetHandlers = packetHandlers;
|
||||||
InstanceHolder.handshakeHandlers = handshakeHandlers;
|
InstanceHolder.handshakeHandlers = handshakeHandlers;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@SuppressWarnings("unchecked")
|
|
||||||
public static <T extends FloodgateApi> T castApi(Class<T> cast) {
|
|
||||||
return (T) api;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,31 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2019-2022 GeyserMC. http://geysermc.org
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
* of this software and associated documentation files (the "Software"), to deal
|
||||||
|
* in the Software without restriction, including without limitation the rights
|
||||||
|
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
* copies of the Software, and to permit persons to whom the Software is
|
||||||
|
* furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in
|
||||||
|
* all copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
|
* THE SOFTWARE.
|
||||||
|
*
|
||||||
|
* @author GeyserMC
|
||||||
|
* @link https://github.com/GeyserMC/Floodgate
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.geysermc.floodgate.api.event;
|
||||||
|
|
||||||
|
import org.geysermc.event.bus.EventBus;
|
||||||
|
|
||||||
|
public interface FloodgateEventBus extends EventBus<Object, FloodgateSubscriber<?>> {
|
||||||
|
}
|
||||||
@@ -0,0 +1,31 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2019-2022 GeyserMC. http://geysermc.org
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
* of this software and associated documentation files (the "Software"), to deal
|
||||||
|
* in the Software without restriction, including without limitation the rights
|
||||||
|
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
* copies of the Software, and to permit persons to whom the Software is
|
||||||
|
* furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in
|
||||||
|
* all copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
|
* THE SOFTWARE.
|
||||||
|
*
|
||||||
|
* @author GeyserMC
|
||||||
|
* @link https://github.com/GeyserMC/Floodgate
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.geysermc.floodgate.api.event;
|
||||||
|
|
||||||
|
import org.geysermc.event.subscribe.Subscriber;
|
||||||
|
|
||||||
|
public interface FloodgateSubscriber<T> extends Subscriber<T> {
|
||||||
|
}
|
||||||
@@ -0,0 +1,74 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2019-2022 GeyserMC. http://geysermc.org
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
* of this software and associated documentation files (the "Software"), to deal
|
||||||
|
* in the Software without restriction, including without limitation the rights
|
||||||
|
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
* copies of the Software, and to permit persons to whom the Software is
|
||||||
|
* furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in
|
||||||
|
* all copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
|
* THE SOFTWARE.
|
||||||
|
*
|
||||||
|
* @author GeyserMC
|
||||||
|
* @link https://github.com/GeyserMC/Floodgate
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.geysermc.floodgate.api.event.skin;
|
||||||
|
|
||||||
|
import org.checkerframework.checker.nullness.qual.NonNull;
|
||||||
|
import org.checkerframework.checker.nullness.qual.Nullable;
|
||||||
|
import org.checkerframework.common.returnsreceiver.qual.This;
|
||||||
|
import org.geysermc.event.Cancellable;
|
||||||
|
import org.geysermc.floodgate.api.player.FloodgatePlayer;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An event that's fired when Floodgate receives a player skin. The event will be cancelled by
|
||||||
|
* default when hasSkin is true, as Floodgate by default only applies skins when the player has no
|
||||||
|
* skin applied yet.
|
||||||
|
*/
|
||||||
|
public interface SkinApplyEvent extends Cancellable {
|
||||||
|
/**
|
||||||
|
* Returns the player that will receive the skin.
|
||||||
|
*/
|
||||||
|
@NonNull FloodgatePlayer player();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the skin texture currently applied to the player.
|
||||||
|
*/
|
||||||
|
@Nullable SkinData currentSkin();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the skin texture to be applied to the player.
|
||||||
|
*/
|
||||||
|
@NonNull SkinData newSkin();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the skin texture to be applied to the player
|
||||||
|
*
|
||||||
|
* @param skinData the skin to apply
|
||||||
|
* @return this
|
||||||
|
*/
|
||||||
|
@This SkinApplyEvent newSkin(@NonNull SkinData skinData);
|
||||||
|
|
||||||
|
interface SkinData {
|
||||||
|
/**
|
||||||
|
* Returns the value of the skin texture.
|
||||||
|
*/
|
||||||
|
@NonNull String value();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the signature of the skin texture.
|
||||||
|
*/
|
||||||
|
@NonNull String signature();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -37,6 +37,7 @@ import org.geysermc.floodgate.util.LinkedPlayer;
|
|||||||
* server. Note that at the time I'm writing this that the HandshakeData is created after requesting
|
* server. Note that at the time I'm writing this that the HandshakeData is created after requesting
|
||||||
* the player link. So the link is present here, if applicable.
|
* the player link. So the link is present here, if applicable.
|
||||||
*/
|
*/
|
||||||
|
@Deprecated
|
||||||
public interface HandshakeData {
|
public interface HandshakeData {
|
||||||
/**
|
/**
|
||||||
* Returns the Channel holding the connection between the client and the server.
|
* Returns the Channel holding the connection between the client and the server.
|
||||||
|
|||||||
@@ -34,6 +34,7 @@ package org.geysermc.floodgate.api.handshake;
|
|||||||
* HandshakeData#isFloodgatePlayer()} will be false and Floodgate related methods will return null
|
* HandshakeData#isFloodgatePlayer()} will be false and Floodgate related methods will return null
|
||||||
* for Java players
|
* for Java players
|
||||||
*/
|
*/
|
||||||
|
@Deprecated
|
||||||
@FunctionalInterface
|
@FunctionalInterface
|
||||||
public interface HandshakeHandler {
|
public interface HandshakeHandler {
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -25,6 +25,13 @@
|
|||||||
|
|
||||||
package org.geysermc.floodgate.api.handshake;
|
package org.geysermc.floodgate.api.handshake;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @deprecated This system has been deprecated and will not be available in the new API that will be
|
||||||
|
* introduced when Geyser will include Floodgate (and thus will have some common base API).
|
||||||
|
* <br>
|
||||||
|
* It might be replaced with an event (probably internal), but that isn't certain yet.
|
||||||
|
*/
|
||||||
|
@Deprecated
|
||||||
public interface HandshakeHandlers {
|
public interface HandshakeHandlers {
|
||||||
/**
|
/**
|
||||||
* Register a custom handshake handler. This can be used to check and edit the player during the
|
* Register a custom handshake handler. This can be used to check and edit the player during the
|
||||||
|
|||||||
@@ -37,10 +37,9 @@ public interface PlatformInjector {
|
|||||||
* Injects the server connection. This will allow various addons (like getting the Floodgate
|
* Injects the server connection. This will allow various addons (like getting the Floodgate
|
||||||
* data and debug mode) to work.
|
* data and debug mode) to work.
|
||||||
*
|
*
|
||||||
* @return true if the connection has successfully been injected
|
* @throws Exception if the platform couldn't be injected
|
||||||
* @throws Exception if something went wrong while injecting the server connection
|
|
||||||
*/
|
*/
|
||||||
boolean inject() throws Exception;
|
void inject() throws Exception;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Some platforms may not be able to remove their injection process. If so, this method will
|
* Some platforms may not be able to remove their injection process. If so, this method will
|
||||||
@@ -56,10 +55,9 @@ public interface PlatformInjector {
|
|||||||
* Removes the injection from the server. Please note that this function should only be used
|
* Removes the injection from the server. Please note that this function should only be used
|
||||||
* internally (on plugin shutdown). This method will also remove every added addon.
|
* internally (on plugin shutdown). This method will also remove every added addon.
|
||||||
*
|
*
|
||||||
* @return true if the injection has successfully been removed
|
* @throws Exception if the platform injection could not be removed
|
||||||
* @throws Exception if something went wrong while removing the injection
|
|
||||||
*/
|
*/
|
||||||
boolean removeInjection() throws Exception;
|
void removeInjection() throws Exception;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* If the server connection is currently injected.
|
* If the server connection is currently injected.
|
||||||
|
|||||||
@@ -34,10 +34,6 @@ public enum LinkRequestResult {
|
|||||||
* An unknown error encountered while creating / verifying the link request.
|
* An unknown error encountered while creating / verifying the link request.
|
||||||
*/
|
*/
|
||||||
UNKNOWN_ERROR,
|
UNKNOWN_ERROR,
|
||||||
/**
|
|
||||||
* @deprecated this result isn't used. Instead the link code is returned
|
|
||||||
*/
|
|
||||||
REQUEST_CREATED,
|
|
||||||
/**
|
/**
|
||||||
* The specified bedrock username is already linked to a Java account.
|
* The specified bedrock username is already linked to a Java account.
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -80,18 +80,7 @@ public interface FloodgateLogger {
|
|||||||
void trace(String message, Object... args);
|
void trace(String message, Object... args);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Enables debug mode for the Floodgate logger.
|
* Returns true if debugging is enabled
|
||||||
*/
|
|
||||||
void enableDebug();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Disables debug mode for the Floodgate logger. Debug messages can still be sent after running
|
|
||||||
* this method, but they will be hidden from the console.
|
|
||||||
*/
|
|
||||||
void disableDebug();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns if debugging is enabled
|
|
||||||
*/
|
*/
|
||||||
boolean isDebug();
|
boolean isDebug();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -143,20 +143,28 @@ public interface FloodgatePlayer {
|
|||||||
return FloodgateApi.getInstance().transferPlayer(getCorrectUniqueId(), address, port);
|
return FloodgateApi.getInstance().transferPlayer(getCorrectUniqueId(), address, port);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Deprecated
|
||||||
boolean hasProperty(PropertyKey key);
|
boolean hasProperty(PropertyKey key);
|
||||||
|
|
||||||
|
@Deprecated
|
||||||
boolean hasProperty(String key);
|
boolean hasProperty(String key);
|
||||||
|
|
||||||
|
@Deprecated
|
||||||
<T> T getProperty(PropertyKey key);
|
<T> T getProperty(PropertyKey key);
|
||||||
|
|
||||||
|
@Deprecated
|
||||||
<T> T getProperty(String key);
|
<T> T getProperty(String key);
|
||||||
|
|
||||||
|
@Deprecated
|
||||||
<T> T removeProperty(PropertyKey key);
|
<T> T removeProperty(PropertyKey key);
|
||||||
|
|
||||||
|
@Deprecated
|
||||||
<T> T removeProperty(String key);
|
<T> T removeProperty(String key);
|
||||||
|
|
||||||
|
@Deprecated
|
||||||
<T> T addProperty(PropertyKey key, Object value);
|
<T> T addProperty(PropertyKey key, Object value);
|
||||||
|
|
||||||
|
@Deprecated
|
||||||
<T> T addProperty(String key, Object value);
|
<T> T addProperty(String key, Object value);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -28,6 +28,7 @@ package org.geysermc.floodgate.api.player;
|
|||||||
import lombok.Getter;
|
import lombok.Getter;
|
||||||
|
|
||||||
@Getter
|
@Getter
|
||||||
|
@Deprecated
|
||||||
public class PropertyKey {
|
public class PropertyKey {
|
||||||
/**
|
/**
|
||||||
* Socket Address returns the InetSocketAddress of the Bedrock player
|
* Socket Address returns the InetSocketAddress of the Bedrock player
|
||||||
|
|||||||
@@ -9,9 +9,10 @@ repositories {
|
|||||||
}
|
}
|
||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
implementation("net.kyori", "indra-common", "2.0.6")
|
implementation("net.kyori", "indra-common", "3.0.1")
|
||||||
implementation("org.jfrog.buildinfo", "build-info-extractor-gradle", "4.26.1")
|
implementation("net.kyori", "indra-git", "3.0.1")
|
||||||
implementation("gradle.plugin.com.github.johnrengelman", "shadow", "7.1.1")
|
implementation("gradle.plugin.com.github.johnrengelman", "shadow", "7.1.1")
|
||||||
|
implementation("gradle.plugin.org.jetbrains.gradle.plugin.idea-ext", "gradle-idea-ext", "1.1.7")
|
||||||
}
|
}
|
||||||
|
|
||||||
tasks.withType<KotlinCompile> {
|
tasks.withType<KotlinCompile> {
|
||||||
|
|||||||
@@ -26,14 +26,15 @@
|
|||||||
object Versions {
|
object Versions {
|
||||||
const val geyserVersion = "2.0.7-SNAPSHOT"
|
const val geyserVersion = "2.0.7-SNAPSHOT"
|
||||||
const val cumulusVersion = "1.1.1"
|
const val cumulusVersion = "1.1.1"
|
||||||
|
const val eventsVersion = "1.0-SNAPSHOT"
|
||||||
const val configUtilsVersion = "1.0-SNAPSHOT"
|
const val configUtilsVersion = "1.0-SNAPSHOT"
|
||||||
const val spigotVersion = "1.13-R0.1-SNAPSHOT"
|
const val spigotVersion = "1.13-R0.1-SNAPSHOT"
|
||||||
const val fastutilVersion = "8.5.3"
|
const val fastutilVersion = "8.5.3"
|
||||||
const val guiceVersion = "5.0.1"
|
const val guiceVersion = "5.1.0"
|
||||||
const val nettyVersion = "4.1.49.Final"
|
const val nettyVersion = "4.1.49.Final"
|
||||||
const val snakeyamlVersion = "1.28"
|
const val snakeyamlVersion = "1.28"
|
||||||
const val cloudVersion = "1.5.0"
|
const val cloudVersion = "1.5.0"
|
||||||
const val bstatsVersion = "3.0.0"
|
const val bstatsVersion = "d2fbbd6823"
|
||||||
|
|
||||||
const val javaWebsocketVersion = "1.5.2"
|
const val javaWebsocketVersion = "1.5.2"
|
||||||
|
|
||||||
|
|||||||
@@ -28,9 +28,6 @@ import org.gradle.api.Project
|
|||||||
import org.gradle.api.artifacts.ProjectDependency
|
import org.gradle.api.artifacts.ProjectDependency
|
||||||
import org.gradle.kotlin.dsl.the
|
import org.gradle.kotlin.dsl.the
|
||||||
|
|
||||||
fun Project.isSnapshot(): Boolean =
|
|
||||||
version.toString().endsWith("-SNAPSHOT")
|
|
||||||
|
|
||||||
fun Project.fullVersion(): String {
|
fun Project.fullVersion(): String {
|
||||||
var version = version.toString()
|
var version = version.toString()
|
||||||
if (version.endsWith("-SNAPSHOT")) {
|
if (version.endsWith("-SNAPSHOT")) {
|
||||||
@@ -42,14 +39,19 @@ fun Project.fullVersion(): String {
|
|||||||
fun Project.lastCommitHash(): String? =
|
fun Project.lastCommitHash(): String? =
|
||||||
the<IndraGitExtension>().commit()?.name?.substring(0, 7)
|
the<IndraGitExtension>().commit()?.name?.substring(0, 7)
|
||||||
|
|
||||||
// retrieved from https://wiki.jenkins-ci.org/display/JENKINS/Building+a+software+project
|
|
||||||
// some properties might be specific to Jenkins
|
|
||||||
fun Project.branchName(): String =
|
fun Project.branchName(): String =
|
||||||
System.getenv("GIT_BRANCH") ?: "local/dev"
|
the<IndraGitExtension>().branchName() ?: System.getenv("BRANCH_NAME") ?: "local/dev"
|
||||||
fun Project.buildNumber(): Int =
|
|
||||||
Integer.parseInt(System.getenv("BUILD_NUMBER") ?: "-1")
|
|
||||||
|
|
||||||
fun Project.buildNumberAsString(): String =
|
fun Project.shouldAddBranchName(): Boolean =
|
||||||
|
System.getenv("IGNORE_BRANCH")?.toBoolean() ?: (branchName() !in arrayOf("master", "local/dev"))
|
||||||
|
|
||||||
|
fun Project.versionWithBranchName(): String =
|
||||||
|
branchName().replace(Regex("[^0-9A-Za-z-_]"), "-") + '-' + version
|
||||||
|
|
||||||
|
fun buildNumber(): Int =
|
||||||
|
System.getenv("BUILD_NUMBER")?.let { Integer.parseInt(it) } ?: -1
|
||||||
|
|
||||||
|
fun buildNumberAsString(): String =
|
||||||
buildNumber().takeIf { it != -1 }?.toString() ?: "??"
|
buildNumber().takeIf { it != -1 }?.toString() ?: "??"
|
||||||
|
|
||||||
val providedDependencies = mutableMapOf<String, MutableSet<Pair<String, Any>>>()
|
val providedDependencies = mutableMapOf<String, MutableSet<Pair<String, Any>>>()
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
plugins {
|
plugins {
|
||||||
`java-library`
|
`java-library`
|
||||||
`maven-publish`
|
|
||||||
// id("net.ltgt.errorprone")
|
// id("net.ltgt.errorprone")
|
||||||
|
id("net.kyori.indra")
|
||||||
id("net.kyori.indra.git")
|
id("net.kyori.indra.git")
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -9,6 +9,21 @@ dependencies {
|
|||||||
compileOnly("org.checkerframework", "checker-qual", Versions.checkerQual)
|
compileOnly("org.checkerframework", "checker-qual", Versions.checkerQual)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
indra {
|
||||||
|
github("GeyserMC", "Floodgate") {
|
||||||
|
ci(true)
|
||||||
|
issues(true)
|
||||||
|
scm(true)
|
||||||
|
}
|
||||||
|
mitLicense()
|
||||||
|
|
||||||
|
javaVersions {
|
||||||
|
// without toolchain & strictVersion sun.misc.Unsafe won't be found
|
||||||
|
minimumToolchain(8)
|
||||||
|
strictVersions(true)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
tasks {
|
tasks {
|
||||||
processResources {
|
processResources {
|
||||||
filesMatching(listOf("plugin.yml", "bungee.yml", "velocity-plugin.json")) {
|
filesMatching(listOf("plugin.yml", "bungee.yml", "velocity-plugin.json")) {
|
||||||
@@ -22,14 +37,4 @@ tasks {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
compileJava {
|
|
||||||
options.encoding = Charsets.UTF_8.name()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
java {
|
|
||||||
sourceCompatibility = JavaVersion.VERSION_1_8
|
|
||||||
targetCompatibility = JavaVersion.VERSION_1_8
|
|
||||||
|
|
||||||
withSourcesJar()
|
|
||||||
}
|
}
|
||||||
@@ -0,0 +1,93 @@
|
|||||||
|
import org.apache.tools.ant.filters.ReplaceTokens
|
||||||
|
import org.gradle.plugins.ide.eclipse.model.EclipseModel
|
||||||
|
import org.gradle.plugins.ide.idea.model.IdeaModel
|
||||||
|
import org.jetbrains.gradle.ext.ProjectSettings
|
||||||
|
import org.jetbrains.gradle.ext.TaskTriggersConfig
|
||||||
|
|
||||||
|
plugins {
|
||||||
|
id("org.jetbrains.gradle.plugin.idea-ext")
|
||||||
|
}
|
||||||
|
|
||||||
|
registerGenerateTemplateTasks()
|
||||||
|
|
||||||
|
fun Project.registerGenerateTemplateTasks() {
|
||||||
|
// main and test
|
||||||
|
extensions.getByType<SourceSetContainer>().all {
|
||||||
|
val javaDestination = layout.buildDirectory.dir("generated/sources/templates/$name")
|
||||||
|
val javaSrcDir = layout.projectDirectory.dir("src/$name/templates")
|
||||||
|
val javaGenerateTask = tasks.register<GenerateSourceTemplates>(
|
||||||
|
getTaskName("template", "sources")
|
||||||
|
) {
|
||||||
|
filteringCharset = Charsets.UTF_8.name()
|
||||||
|
from(javaSrcDir)
|
||||||
|
into(javaDestination)
|
||||||
|
filter<ReplaceTokens>("tokens" to replacements())
|
||||||
|
}
|
||||||
|
java.srcDir(javaGenerateTask.map { it.outputs })
|
||||||
|
|
||||||
|
val resourcesDestination = layout.buildDirectory.dir("generated/resources/templates/$name")
|
||||||
|
val resourcesSrcDir = layout.projectDirectory.dir("src/$name/resourceTemplates")
|
||||||
|
val resourcesGenerateTask = tasks.register<GenerateResourceTemplates>(
|
||||||
|
getTaskName("template", "resources")
|
||||||
|
) {
|
||||||
|
filteringCharset = Charsets.UTF_8.name()
|
||||||
|
from(resourcesSrcDir)
|
||||||
|
into(resourcesDestination)
|
||||||
|
filter<ReplaceTokens>("tokens" to replacements())
|
||||||
|
}
|
||||||
|
resources.srcDir(resourcesGenerateTask.map { it.outputs })
|
||||||
|
}
|
||||||
|
|
||||||
|
return configureIdeSync(
|
||||||
|
tasks.register("allTemplateSources") {
|
||||||
|
dependsOn(tasks.withType<GenerateSourceTemplates>())
|
||||||
|
},
|
||||||
|
tasks.register("allTemplateResources") {
|
||||||
|
dependsOn(tasks.withType<GenerateResourceTemplates>())
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun Project.configureIdeSync(vararg generateAllTasks: TaskProvider<Task>) {
|
||||||
|
extensions.findByType<EclipseModel> {
|
||||||
|
synchronizationTasks(generateAllTasks)
|
||||||
|
}
|
||||||
|
|
||||||
|
extensions.findByType<IdeaModel> {
|
||||||
|
if (project != null) {
|
||||||
|
(project as ExtensionAware).extensions.configure<ProjectSettings> {
|
||||||
|
(this as ExtensionAware).extensions.configure<TaskTriggersConfig> {
|
||||||
|
afterSync(generateAllTasks)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//todo wasn't able to find something for VS(Code)
|
||||||
|
}
|
||||||
|
|
||||||
|
inline fun <reified T : Any> ExtensionContainer.findByType(noinline action: T.() -> Unit) {
|
||||||
|
val extension = findByType(T::class)
|
||||||
|
if (extension != null) {
|
||||||
|
action.invoke(extension)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
abstract class GenerateAnyTemplates : Copy() {
|
||||||
|
private val replacements = mutableMapOf<String, String>()
|
||||||
|
|
||||||
|
fun replaceToken(key: String, value: () -> Any) {
|
||||||
|
replaceToken(key, value.invoke())
|
||||||
|
}
|
||||||
|
|
||||||
|
fun replaceToken(key: String, value: Any) {
|
||||||
|
replacements[key] = value.toString()
|
||||||
|
}
|
||||||
|
|
||||||
|
fun replacements(): Map<String, String> {
|
||||||
|
return replacements
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
open class GenerateResourceTemplates : GenerateAnyTemplates()
|
||||||
|
open class GenerateSourceTemplates : GenerateAnyTemplates()
|
||||||
@@ -1,34 +1,15 @@
|
|||||||
plugins {
|
plugins {
|
||||||
id("floodgate.shadow-conventions")
|
id("floodgate.shadow-conventions")
|
||||||
id("com.jfrog.artifactory")
|
id("net.kyori.indra.publishing")
|
||||||
id("maven-publish")
|
|
||||||
}
|
}
|
||||||
|
|
||||||
publishing {
|
indra {
|
||||||
publications {
|
configurePublications {
|
||||||
create<MavenPublication>("mavenJava") {
|
if (shouldAddBranchName()) {
|
||||||
groupId = project.group as String
|
version = versionWithBranchName()
|
||||||
artifactId = project.name
|
|
||||||
version = project.version as String
|
|
||||||
|
|
||||||
artifact(tasks["shadowJar"])
|
|
||||||
artifact(tasks["sourcesJar"])
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
artifactory {
|
publishSnapshotsTo("geysermc", "https://repo.opencollab.dev/maven-snapshots")
|
||||||
setContextUrl("https://repo.opencollab.dev/artifactory")
|
publishReleasesTo("geysermc", "https://repo.opencollab.dev/maven-releases")
|
||||||
publish {
|
|
||||||
repository {
|
|
||||||
setRepoKey(if (isSnapshot()) "maven-snapshots" else "maven-releases")
|
|
||||||
setMavenCompatible(true)
|
|
||||||
}
|
|
||||||
defaults {
|
|
||||||
publications("mavenJava")
|
|
||||||
setPublishArtifacts(true)
|
|
||||||
setPublishPom(true)
|
|
||||||
setPublishIvy(false)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
@@ -31,6 +31,11 @@ tasks {
|
|||||||
// for example Velocity, the relocation will be gone for Velocity)
|
// for example Velocity, the relocation will be gone for Velocity)
|
||||||
addRelocations(project, sJar)
|
addRelocations(project, sJar)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
val destinationDir = System.getenv("DESTINATION_DIRECTORY");
|
||||||
|
if (destinationDir != null) {
|
||||||
|
destinationDirectory.set(file(destinationDir))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
named("build") {
|
named("build") {
|
||||||
dependsOn(shadowJar)
|
dependsOn(shadowJar)
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ plugins {
|
|||||||
|
|
||||||
allprojects {
|
allprojects {
|
||||||
group = "org.geysermc.floodgate"
|
group = "org.geysermc.floodgate"
|
||||||
version = "2.2.0-SNAPSHOT"
|
version = property("version")!!
|
||||||
description = "Allows Bedrock players to join Java edition servers while keeping the server in online mode"
|
description = "Allows Bedrock players to join Java edition servers while keeping the server in online mode"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -49,8 +49,7 @@ public final class BungeeInjector extends CommonPlatformInjector {
|
|||||||
@Getter private boolean injected;
|
@Getter private boolean injected;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean inject() {
|
public void inject() {
|
||||||
try {
|
|
||||||
// Can everyone just switch to Velocity please :)
|
// Can everyone just switch to Velocity please :)
|
||||||
|
|
||||||
Field framePrepender = ReflectionUtils.getField(PipelineUtils.class, "framePrepender");
|
Field framePrepender = ReflectionUtils.getField(PipelineUtils.class, "framePrepender");
|
||||||
@@ -65,11 +64,6 @@ public final class BungeeInjector extends CommonPlatformInjector {
|
|||||||
BungeeReflectionUtils.setFieldValue(null, framePrepender, customPrepender);
|
BungeeReflectionUtils.setFieldValue(null, framePrepender, customPrepender);
|
||||||
|
|
||||||
injected = true;
|
injected = true;
|
||||||
return true;
|
|
||||||
} catch (Exception e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -78,9 +72,9 @@ public final class BungeeInjector extends CommonPlatformInjector {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean removeInjection() {
|
public void removeInjection() {
|
||||||
logger.error("Floodgate cannot remove itself from Bungee without a reboot");
|
throw new IllegalStateException(
|
||||||
return false;
|
"Floodgate cannot remove itself from Bungee without a reboot");
|
||||||
}
|
}
|
||||||
|
|
||||||
void injectClient(Channel channel, boolean clientToProxy) {
|
void injectClient(Channel channel, boolean clientToProxy) {
|
||||||
|
|||||||
@@ -48,7 +48,7 @@ import org.geysermc.floodgate.api.logger.FloodgateLogger;
|
|||||||
import org.geysermc.floodgate.api.player.FloodgatePlayer;
|
import org.geysermc.floodgate.api.player.FloodgatePlayer;
|
||||||
import org.geysermc.floodgate.config.ProxyFloodgateConfig;
|
import org.geysermc.floodgate.config.ProxyFloodgateConfig;
|
||||||
import org.geysermc.floodgate.skin.SkinApplier;
|
import org.geysermc.floodgate.skin.SkinApplier;
|
||||||
import org.geysermc.floodgate.skin.SkinData;
|
import org.geysermc.floodgate.skin.SkinDataImpl;
|
||||||
import org.geysermc.floodgate.util.LanguageManager;
|
import org.geysermc.floodgate.util.LanguageManager;
|
||||||
import org.geysermc.floodgate.util.ReflectionUtils;
|
import org.geysermc.floodgate.util.ReflectionUtils;
|
||||||
|
|
||||||
@@ -131,7 +131,7 @@ public final class BungeeListener implements Listener {
|
|||||||
if (!config.isSendFloodgateData()) {
|
if (!config.isSendFloodgateData()) {
|
||||||
FloodgatePlayer player = api.getPlayer(event.getPlayer().getUniqueId());
|
FloodgatePlayer player = api.getPlayer(event.getPlayer().getUniqueId());
|
||||||
if (player != null && !player.isLinked()) {
|
if (player != null && !player.isLinked()) {
|
||||||
skinApplier.applySkin(player, new SkinData("", ""));
|
skinApplier.applySkin(player, new SkinDataImpl("", ""));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -32,6 +32,8 @@ import com.google.inject.AbstractModule;
|
|||||||
import com.google.inject.Provides;
|
import com.google.inject.Provides;
|
||||||
import com.google.inject.Singleton;
|
import com.google.inject.Singleton;
|
||||||
import com.google.inject.name.Named;
|
import com.google.inject.name.Named;
|
||||||
|
import com.google.inject.name.Names;
|
||||||
|
import java.util.logging.Logger;
|
||||||
import lombok.RequiredArgsConstructor;
|
import lombok.RequiredArgsConstructor;
|
||||||
import net.md_5.bungee.api.CommandSender;
|
import net.md_5.bungee.api.CommandSender;
|
||||||
import net.md_5.bungee.api.plugin.Listener;
|
import net.md_5.bungee.api.plugin.Listener;
|
||||||
@@ -66,6 +68,9 @@ public final class BungeePlatformModule extends AbstractModule {
|
|||||||
@Override
|
@Override
|
||||||
protected void configure() {
|
protected void configure() {
|
||||||
bind(PlatformUtils.class).to(BungeePlatformUtils.class);
|
bind(PlatformUtils.class).to(BungeePlatformUtils.class);
|
||||||
|
bind(Logger.class).annotatedWith(Names.named("logger")).toInstance(plugin.getLogger());
|
||||||
|
bind(FloodgateLogger.class).to(JavaUtilFloodgateLogger.class);
|
||||||
|
bind(SkinApplier.class).to(BungeeSkinApplier.class);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Provides
|
@Provides
|
||||||
@@ -74,12 +79,6 @@ public final class BungeePlatformModule extends AbstractModule {
|
|||||||
return plugin;
|
return plugin;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Provides
|
|
||||||
@Singleton
|
|
||||||
public FloodgateLogger floodgateLogger(LanguageManager languageManager) {
|
|
||||||
return new JavaUtilFloodgateLogger(plugin.getLogger(), languageManager);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Commands / Listeners
|
Commands / Listeners
|
||||||
*/
|
*/
|
||||||
@@ -123,12 +122,6 @@ public final class BungeePlatformModule extends AbstractModule {
|
|||||||
return new BungeePluginMessageRegistration();
|
return new BungeePluginMessageRegistration();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Provides
|
|
||||||
@Singleton
|
|
||||||
public SkinApplier skinApplier(FloodgateLogger logger) {
|
|
||||||
return new BungeeSkinApplier(logger);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
DebugAddon / PlatformInjector
|
DebugAddon / PlatformInjector
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -53,21 +53,6 @@ public final class BungeePluginMessageUtils extends PluginMessageUtils implement
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
UUID targetUuid = null;
|
|
||||||
String targetUsername = null;
|
|
||||||
Identity targetIdentity = Identity.UNKNOWN;
|
|
||||||
|
|
||||||
Connection target = event.getReceiver();
|
|
||||||
if (target instanceof ProxiedPlayer) {
|
|
||||||
ProxiedPlayer player = (ProxiedPlayer) target;
|
|
||||||
targetUuid = player.getUniqueId();
|
|
||||||
targetUsername = player.getName();
|
|
||||||
targetIdentity = Identity.PLAYER;
|
|
||||||
|
|
||||||
} else if (target instanceof ServerConnection) {
|
|
||||||
targetIdentity = Identity.SERVER;
|
|
||||||
}
|
|
||||||
|
|
||||||
UUID sourceUuid = null;
|
UUID sourceUuid = null;
|
||||||
String sourceUsername = null;
|
String sourceUsername = null;
|
||||||
Identity sourceIdentity = Identity.UNKNOWN;
|
Identity sourceIdentity = Identity.UNKNOWN;
|
||||||
@@ -83,8 +68,9 @@ public final class BungeePluginMessageUtils extends PluginMessageUtils implement
|
|||||||
sourceIdentity = Identity.SERVER;
|
sourceIdentity = Identity.SERVER;
|
||||||
}
|
}
|
||||||
|
|
||||||
Result result = channel.handleProxyCall(event.getData(), targetUuid, targetUsername,
|
Result result = channel.handleProxyCall(
|
||||||
targetIdentity, sourceUuid, sourceUsername, sourceIdentity);
|
event.getData(), sourceUuid, sourceUsername, sourceIdentity
|
||||||
|
);
|
||||||
|
|
||||||
event.setCancelled(!result.isAllowed());
|
event.setCancelled(!result.isAllowed());
|
||||||
|
|
||||||
|
|||||||
@@ -26,61 +26,46 @@
|
|||||||
package org.geysermc.floodgate.pluginmessage;
|
package org.geysermc.floodgate.pluginmessage;
|
||||||
|
|
||||||
import static com.google.common.base.Preconditions.checkNotNull;
|
import static com.google.common.base.Preconditions.checkNotNull;
|
||||||
import static org.geysermc.floodgate.util.ReflectionUtils.getConstructor;
|
|
||||||
import static org.geysermc.floodgate.util.ReflectionUtils.getFieldOfType;
|
import static org.geysermc.floodgate.util.ReflectionUtils.getFieldOfType;
|
||||||
import static org.geysermc.floodgate.util.ReflectionUtils.getMethodByName;
|
|
||||||
|
|
||||||
import java.lang.reflect.Array;
|
import com.google.inject.Inject;
|
||||||
import java.lang.reflect.Constructor;
|
import com.google.inject.Singleton;
|
||||||
import java.lang.reflect.Field;
|
import java.lang.reflect.Field;
|
||||||
import java.lang.reflect.Method;
|
import java.util.ArrayList;
|
||||||
import lombok.RequiredArgsConstructor;
|
import java.util.List;
|
||||||
import net.md_5.bungee.api.ProxyServer;
|
import net.md_5.bungee.api.ProxyServer;
|
||||||
import net.md_5.bungee.api.connection.ProxiedPlayer;
|
import net.md_5.bungee.api.connection.ProxiedPlayer;
|
||||||
import net.md_5.bungee.connection.InitialHandler;
|
import net.md_5.bungee.connection.InitialHandler;
|
||||||
import net.md_5.bungee.connection.LoginResult;
|
import net.md_5.bungee.connection.LoginResult;
|
||||||
|
import net.md_5.bungee.protocol.Property;
|
||||||
|
import org.checkerframework.checker.nullness.qual.NonNull;
|
||||||
|
import org.geysermc.floodgate.api.event.skin.SkinApplyEvent;
|
||||||
|
import org.geysermc.floodgate.api.event.skin.SkinApplyEvent.SkinData;
|
||||||
import org.geysermc.floodgate.api.logger.FloodgateLogger;
|
import org.geysermc.floodgate.api.logger.FloodgateLogger;
|
||||||
import org.geysermc.floodgate.api.player.FloodgatePlayer;
|
import org.geysermc.floodgate.api.player.FloodgatePlayer;
|
||||||
|
import org.geysermc.floodgate.event.EventBus;
|
||||||
|
import org.geysermc.floodgate.event.skin.SkinApplyEventImpl;
|
||||||
import org.geysermc.floodgate.skin.SkinApplier;
|
import org.geysermc.floodgate.skin.SkinApplier;
|
||||||
import org.geysermc.floodgate.skin.SkinData;
|
import org.geysermc.floodgate.skin.SkinDataImpl;
|
||||||
import org.geysermc.floodgate.util.ReflectionUtils;
|
import org.geysermc.floodgate.util.ReflectionUtils;
|
||||||
|
|
||||||
@RequiredArgsConstructor
|
@Singleton
|
||||||
public final class BungeeSkinApplier implements SkinApplier {
|
public final class BungeeSkinApplier implements SkinApplier {
|
||||||
private static final Constructor<?> LOGIN_RESULT_CONSTRUCTOR;
|
|
||||||
private static final Field LOGIN_RESULT_FIELD;
|
private static final Field LOGIN_RESULT_FIELD;
|
||||||
private static final Method SET_PROPERTIES_METHOD;
|
|
||||||
|
|
||||||
private static final Class<?> PROPERTY_CLASS;
|
|
||||||
private static final Constructor<?> PROPERTY_CONSTRUCTOR;
|
|
||||||
|
|
||||||
static {
|
static {
|
||||||
PROPERTY_CLASS = ReflectionUtils.getClassOrFallbackPrefixed(
|
|
||||||
"protocol.Property", "connection.LoginResult$Property"
|
|
||||||
);
|
|
||||||
|
|
||||||
LOGIN_RESULT_CONSTRUCTOR = getConstructor(
|
|
||||||
LoginResult.class, true,
|
|
||||||
String.class, String.class, Array.newInstance(PROPERTY_CLASS, 0).getClass()
|
|
||||||
);
|
|
||||||
|
|
||||||
LOGIN_RESULT_FIELD = getFieldOfType(InitialHandler.class, LoginResult.class);
|
LOGIN_RESULT_FIELD = getFieldOfType(InitialHandler.class, LoginResult.class);
|
||||||
checkNotNull(LOGIN_RESULT_FIELD, "LoginResult field cannot be null");
|
checkNotNull(LOGIN_RESULT_FIELD, "LoginResult field cannot be null");
|
||||||
|
|
||||||
SET_PROPERTIES_METHOD = getMethodByName(LoginResult.class, "setProperties", true);
|
|
||||||
|
|
||||||
PROPERTY_CONSTRUCTOR = ReflectionUtils.getConstructor(
|
|
||||||
PROPERTY_CLASS, true,
|
|
||||||
String.class, String.class, String.class
|
|
||||||
);
|
|
||||||
checkNotNull(PROPERTY_CONSTRUCTOR, "Property constructor cannot be null");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private final FloodgateLogger logger;
|
private final ProxyServer server = ProxyServer.getInstance();
|
||||||
|
|
||||||
|
@Inject private EventBus eventBus;
|
||||||
|
@Inject private FloodgateLogger logger;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void applySkin(FloodgatePlayer uuid, SkinData skinData) {
|
public void applySkin(@NonNull FloodgatePlayer floodgatePlayer, @NonNull SkinData skinData) {
|
||||||
ProxiedPlayer player = ProxyServer.getInstance().getPlayer(uuid.getCorrectUniqueId());
|
ProxiedPlayer player = server.getPlayer(floodgatePlayer.getCorrectUniqueId());
|
||||||
if (player == null) {
|
if (player == null) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -97,21 +82,46 @@ public final class BungeeSkinApplier implements SkinApplier {
|
|||||||
// expected to be null since LoginResult is the data from hasJoined,
|
// expected to be null since LoginResult is the data from hasJoined,
|
||||||
// which Floodgate players don't have
|
// which Floodgate players don't have
|
||||||
if (loginResult == null) {
|
if (loginResult == null) {
|
||||||
// id and name are unused and properties will be overridden
|
// id and name are unused
|
||||||
loginResult = (LoginResult) ReflectionUtils.newInstance(
|
loginResult = new LoginResult(null, null, new Property[0]);
|
||||||
LOGIN_RESULT_CONSTRUCTOR, null, null, null
|
|
||||||
);
|
|
||||||
ReflectionUtils.setValue(handler, LOGIN_RESULT_FIELD, loginResult);
|
ReflectionUtils.setValue(handler, LOGIN_RESULT_FIELD, loginResult);
|
||||||
}
|
}
|
||||||
|
|
||||||
Object property = ReflectionUtils.newInstance(
|
Property[] properties = loginResult.getProperties();
|
||||||
PROPERTY_CONSTRUCTOR,
|
|
||||||
"textures", skinData.getValue(), skinData.getSignature()
|
|
||||||
);
|
|
||||||
|
|
||||||
Object propertyArray = Array.newInstance(PROPERTY_CLASS, 1);
|
SkinData currentSkin = currentSkin(properties);
|
||||||
Array.set(propertyArray, 0, property);
|
|
||||||
|
|
||||||
ReflectionUtils.invoke(loginResult, SET_PROPERTIES_METHOD, propertyArray);
|
SkinApplyEvent event = new SkinApplyEventImpl(floodgatePlayer, currentSkin, skinData);
|
||||||
|
event.setCancelled(floodgatePlayer.isLinked());
|
||||||
|
|
||||||
|
eventBus.fire(event);
|
||||||
|
|
||||||
|
if (event.isCancelled()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
loginResult.setProperties(replaceSkin(properties, event.newSkin()));
|
||||||
|
}
|
||||||
|
|
||||||
|
private SkinData currentSkin(Property[] properties) {
|
||||||
|
for (Property property : properties) {
|
||||||
|
if (property.getName().equals("textures")) {
|
||||||
|
if (!property.getValue().isEmpty()) {
|
||||||
|
return new SkinDataImpl(property.getValue(), property.getSignature());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
private Property[] replaceSkin(Property[] properties, SkinData skinData) {
|
||||||
|
List<Property> list = new ArrayList<>();
|
||||||
|
for (Property property : properties) {
|
||||||
|
if (!property.getName().equals("textures")) {
|
||||||
|
list.add(property);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
list.add(new Property("textures", skinData.value(), skinData.signature()));
|
||||||
|
return list.toArray(new Property[0]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,20 +1,23 @@
|
|||||||
import net.kyori.blossom.BlossomExtension
|
|
||||||
|
|
||||||
plugins {
|
plugins {
|
||||||
id("net.kyori.blossom")
|
id("floodgate.generate-templates")
|
||||||
}
|
}
|
||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
api(projects.api)
|
api(projects.api)
|
||||||
api("org.geysermc.configutils", "configutils", Versions.configUtilsVersion)
|
api("org.geysermc.configutils", "configutils", Versions.configUtilsVersion)
|
||||||
|
|
||||||
|
compileOnly(projects.ap)
|
||||||
|
annotationProcessor(projects.ap)
|
||||||
|
|
||||||
api("com.google.inject", "guice", Versions.guiceVersion)
|
api("com.google.inject", "guice", Versions.guiceVersion)
|
||||||
api("com.nukkitx.fastutil", "fastutil-short-object-maps", Versions.fastutilVersion)
|
api("com.nukkitx.fastutil", "fastutil-short-object-maps", Versions.fastutilVersion)
|
||||||
api("com.nukkitx.fastutil", "fastutil-int-object-maps", Versions.fastutilVersion)
|
api("com.nukkitx.fastutil", "fastutil-int-object-maps", Versions.fastutilVersion)
|
||||||
api("org.java-websocket", "Java-WebSocket", Versions.javaWebsocketVersion)
|
api("org.java-websocket", "Java-WebSocket", Versions.javaWebsocketVersion)
|
||||||
api("cloud.commandframework", "cloud-core", Versions.cloudVersion)
|
api("cloud.commandframework", "cloud-core", Versions.cloudVersion)
|
||||||
api("org.yaml", "snakeyaml", Versions.snakeyamlVersion)
|
api("org.yaml", "snakeyaml", Versions.snakeyamlVersion)
|
||||||
api("org.bstats", "bstats-base", Versions.bstatsVersion)
|
|
||||||
|
//todo use official dependency once https://github.com/Bastian/bstats-metrics/pull/118 is merged
|
||||||
|
api("com.github.Konicai.bstats-metrics", "bstats-base", Versions.bstatsVersion)
|
||||||
}
|
}
|
||||||
|
|
||||||
// present on all platforms
|
// present on all platforms
|
||||||
@@ -23,9 +26,10 @@ provided("io.netty", "netty-codec", Versions.nettyVersion)
|
|||||||
|
|
||||||
relocate("org.bstats")
|
relocate("org.bstats")
|
||||||
|
|
||||||
configure<BlossomExtension> {
|
tasks {
|
||||||
val constantsFile = "src/main/java/org/geysermc/floodgate/util/Constants.java"
|
templateSources {
|
||||||
replaceToken("\${floodgateVersion}", fullVersion(), constantsFile)
|
replaceToken("floodgateVersion", fullVersion())
|
||||||
replaceToken("\${branch}", branchName(), constantsFile)
|
replaceToken("branch", branchName())
|
||||||
replaceToken("\${buildNumber}", buildNumber(), constantsFile)
|
replaceToken("buildNumber", buildNumber())
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -28,121 +28,66 @@ package org.geysermc.floodgate;
|
|||||||
import com.google.inject.Inject;
|
import com.google.inject.Inject;
|
||||||
import com.google.inject.Injector;
|
import com.google.inject.Injector;
|
||||||
import com.google.inject.Module;
|
import com.google.inject.Module;
|
||||||
import com.google.inject.name.Named;
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.nio.file.Files;
|
|
||||||
import java.nio.file.Path;
|
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
import org.geysermc.floodgate.api.FloodgateApi;
|
import org.geysermc.floodgate.api.FloodgateApi;
|
||||||
import org.geysermc.floodgate.api.InstanceHolder;
|
import org.geysermc.floodgate.api.InstanceHolder;
|
||||||
|
import org.geysermc.floodgate.api.event.FloodgateEventBus;
|
||||||
import org.geysermc.floodgate.api.handshake.HandshakeHandlers;
|
import org.geysermc.floodgate.api.handshake.HandshakeHandlers;
|
||||||
import org.geysermc.floodgate.api.inject.PlatformInjector;
|
import org.geysermc.floodgate.api.inject.PlatformInjector;
|
||||||
import org.geysermc.floodgate.api.link.PlayerLink;
|
import org.geysermc.floodgate.api.link.PlayerLink;
|
||||||
import org.geysermc.floodgate.api.logger.FloodgateLogger;
|
|
||||||
import org.geysermc.floodgate.api.packet.PacketHandlers;
|
import org.geysermc.floodgate.api.packet.PacketHandlers;
|
||||||
import org.geysermc.floodgate.config.ConfigLoader;
|
|
||||||
import org.geysermc.floodgate.config.FloodgateConfig;
|
import org.geysermc.floodgate.config.FloodgateConfig;
|
||||||
import org.geysermc.floodgate.config.FloodgateConfigHolder;
|
import org.geysermc.floodgate.event.EventBus;
|
||||||
import org.geysermc.floodgate.link.PlayerLinkLoader;
|
import org.geysermc.floodgate.event.lifecycle.PostEnableEvent;
|
||||||
import org.geysermc.floodgate.module.ConfigLoadedModule;
|
import org.geysermc.floodgate.event.lifecycle.ShutdownEvent;
|
||||||
import org.geysermc.floodgate.module.PostInitializeModule;
|
import org.geysermc.floodgate.module.PostInitializeModule;
|
||||||
import org.geysermc.floodgate.news.NewsChecker;
|
|
||||||
import org.geysermc.floodgate.util.Metrics;
|
|
||||||
import org.geysermc.floodgate.util.PrefixCheckTask;
|
|
||||||
|
|
||||||
public class FloodgatePlatform {
|
public class FloodgatePlatform {
|
||||||
private static final UUID KEY = UUID.randomUUID();
|
private static final UUID KEY = UUID.randomUUID();
|
||||||
private final FloodgateApi api;
|
@Inject private PlatformInjector injector;
|
||||||
private final PlatformInjector injector;
|
|
||||||
|
|
||||||
private final FloodgateLogger logger;
|
@Inject private FloodgateConfig config;
|
||||||
|
@Inject private Injector guice;
|
||||||
private FloodgateConfig config;
|
|
||||||
private Injector guice;
|
|
||||||
|
|
||||||
@Inject
|
|
||||||
public FloodgatePlatform(
|
|
||||||
FloodgateApi api,
|
|
||||||
PlatformInjector platformInjector,
|
|
||||||
FloodgateLogger logger,
|
|
||||||
Injector guice) {
|
|
||||||
|
|
||||||
this.api = api;
|
|
||||||
this.injector = platformInjector;
|
|
||||||
this.logger = logger;
|
|
||||||
this.guice = guice;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Inject
|
@Inject
|
||||||
public void init(
|
public void init(
|
||||||
@Named("dataDirectory") Path dataDirectory,
|
FloodgateApi api,
|
||||||
ConfigLoader configLoader,
|
PlayerLink link,
|
||||||
FloodgateConfigHolder configHolder,
|
FloodgateEventBus eventBus,
|
||||||
PacketHandlers packetHandlers,
|
PacketHandlers packetHandlers,
|
||||||
HandshakeHandlers handshakeHandlers) {
|
HandshakeHandlers handshakeHandlers
|
||||||
|
) {
|
||||||
if (!Files.isDirectory(dataDirectory)) {
|
InstanceHolder.set(
|
||||||
try {
|
api, link, eventBus, this.injector, packetHandlers, handshakeHandlers, KEY
|
||||||
Files.createDirectory(dataDirectory);
|
);
|
||||||
} catch (IOException exception) {
|
|
||||||
logger.error("Failed to create the data folder", exception);
|
|
||||||
throw new RuntimeException("Failed to create the data folder", exception);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
config = configLoader.load();
|
public void enable(Module... postInitializeModules) throws RuntimeException {
|
||||||
if (config.isDebug()) {
|
|
||||||
logger.enableDebug();
|
|
||||||
}
|
|
||||||
|
|
||||||
configHolder.set(config);
|
|
||||||
guice = guice.createChildInjector(new ConfigLoadedModule(config));
|
|
||||||
PlayerLink link = guice.getInstance(PlayerLinkLoader.class).load();
|
|
||||||
|
|
||||||
InstanceHolder.set(api, link, this.injector, packetHandlers, handshakeHandlers, KEY);
|
|
||||||
|
|
||||||
guice.getInstance(NewsChecker.class).start();
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean enable(Module... postInitializeModules) {
|
|
||||||
if (injector == null) {
|
if (injector == null) {
|
||||||
logger.error("Failed to find the platform injector!");
|
throw new RuntimeException("Failed to find the platform injector!");
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
if (!injector.inject()) {
|
injector.inject();
|
||||||
logger.error("Failed to inject the packet listener!");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
} catch (Exception exception) {
|
} catch (Exception exception) {
|
||||||
logger.error("Failed to inject the packet listener!", exception);
|
throw new RuntimeException("Failed to inject the packet listener!", exception);
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
this.guice = guice.createChildInjector(new PostInitializeModule(postInitializeModules));
|
this.guice = guice.createChildInjector(new PostInitializeModule(postInitializeModules));
|
||||||
|
|
||||||
PrefixCheckTask.checkAndExecuteDelayed(config, logger);
|
guice.getInstance(EventBus.class).fire(new PostEnableEvent());
|
||||||
|
|
||||||
guice.getInstance(Metrics.class);
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean disable() {
|
public void disable() {
|
||||||
|
guice.getInstance(EventBus.class).fire(new ShutdownEvent());
|
||||||
|
|
||||||
if (injector != null && injector.canRemoveInjection()) {
|
if (injector != null && injector.canRemoveInjection()) {
|
||||||
try {
|
try {
|
||||||
if (!injector.removeInjection()) {
|
injector.removeInjection();
|
||||||
logger.error("Failed to remove the injection!");
|
|
||||||
}
|
|
||||||
} catch (Exception exception) {
|
} catch (Exception exception) {
|
||||||
logger.error("Failed to remove the injection!", exception);
|
throw new RuntimeException("Failed to remove the injection!", exception);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
guice.getInstance(NewsChecker.class).shutdown();
|
|
||||||
api.getPlayerLink().stop();
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean isProxy() {
|
public boolean isProxy() {
|
||||||
|
|||||||
@@ -25,24 +25,14 @@
|
|||||||
|
|
||||||
package org.geysermc.floodgate.api;
|
package org.geysermc.floodgate.api;
|
||||||
|
|
||||||
|
import com.google.inject.Inject;
|
||||||
import java.nio.charset.StandardCharsets;
|
import java.nio.charset.StandardCharsets;
|
||||||
import org.geysermc.floodgate.api.logger.FloodgateLogger;
|
|
||||||
import org.geysermc.floodgate.config.FloodgateConfigHolder;
|
|
||||||
import org.geysermc.floodgate.crypto.FloodgateCipher;
|
import org.geysermc.floodgate.crypto.FloodgateCipher;
|
||||||
import org.geysermc.floodgate.pluginmessage.PluginMessageManager;
|
|
||||||
import org.geysermc.floodgate.util.BedrockData;
|
import org.geysermc.floodgate.util.BedrockData;
|
||||||
|
|
||||||
public final class ProxyFloodgateApi extends SimpleFloodgateApi {
|
public final class ProxyFloodgateApi extends SimpleFloodgateApi {
|
||||||
private final FloodgateCipher cipher;
|
@Inject
|
||||||
|
private FloodgateCipher cipher;
|
||||||
public ProxyFloodgateApi(
|
|
||||||
PluginMessageManager pluginMessageManager,
|
|
||||||
FloodgateConfigHolder configHolder,
|
|
||||||
FloodgateLogger logger,
|
|
||||||
FloodgateCipher cipher) {
|
|
||||||
super(pluginMessageManager, configHolder, logger);
|
|
||||||
this.cipher = cipher;
|
|
||||||
}
|
|
||||||
|
|
||||||
public byte[] createEncryptedData(BedrockData bedrockData) {
|
public byte[] createEncryptedData(BedrockData bedrockData) {
|
||||||
try {
|
try {
|
||||||
|
|||||||
@@ -30,41 +30,41 @@ import com.google.common.cache.CacheBuilder;
|
|||||||
import com.google.common.collect.ImmutableSet;
|
import com.google.common.collect.ImmutableSet;
|
||||||
import com.google.gson.JsonElement;
|
import com.google.gson.JsonElement;
|
||||||
import com.google.gson.JsonObject;
|
import com.google.gson.JsonObject;
|
||||||
|
import com.google.inject.Inject;
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
import java.util.HashMap;
|
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
import java.util.concurrent.CompletableFuture;
|
import java.util.concurrent.CompletableFuture;
|
||||||
|
import java.util.concurrent.ConcurrentHashMap;
|
||||||
import java.util.concurrent.TimeUnit;
|
import java.util.concurrent.TimeUnit;
|
||||||
import lombok.RequiredArgsConstructor;
|
|
||||||
import org.geysermc.cumulus.form.Form;
|
import org.geysermc.cumulus.form.Form;
|
||||||
import org.geysermc.cumulus.form.util.FormBuilder;
|
import org.geysermc.cumulus.form.util.FormBuilder;
|
||||||
import org.geysermc.floodgate.api.logger.FloodgateLogger;
|
import org.geysermc.floodgate.api.logger.FloodgateLogger;
|
||||||
import org.geysermc.floodgate.api.player.FloodgatePlayer;
|
import org.geysermc.floodgate.api.player.FloodgatePlayer;
|
||||||
import org.geysermc.floodgate.api.unsafe.Unsafe;
|
import org.geysermc.floodgate.api.unsafe.Unsafe;
|
||||||
import org.geysermc.floodgate.config.FloodgateConfigHolder;
|
import org.geysermc.floodgate.config.FloodgateConfig;
|
||||||
import org.geysermc.floodgate.pluginmessage.PluginMessageManager;
|
import org.geysermc.floodgate.pluginmessage.PluginMessageManager;
|
||||||
import org.geysermc.floodgate.pluginmessage.channel.FormChannel;
|
import org.geysermc.floodgate.pluginmessage.channel.FormChannel;
|
||||||
import org.geysermc.floodgate.pluginmessage.channel.TransferChannel;
|
import org.geysermc.floodgate.pluginmessage.channel.TransferChannel;
|
||||||
import org.geysermc.floodgate.util.Constants;
|
import org.geysermc.floodgate.util.Constants;
|
||||||
import org.geysermc.floodgate.util.HttpUtils;
|
import org.geysermc.floodgate.util.HttpClient;
|
||||||
import org.geysermc.floodgate.util.Utils;
|
import org.geysermc.floodgate.util.Utils;
|
||||||
|
|
||||||
@RequiredArgsConstructor
|
|
||||||
public class SimpleFloodgateApi implements FloodgateApi {
|
public class SimpleFloodgateApi implements FloodgateApi {
|
||||||
private final Map<UUID, FloodgatePlayer> players = new HashMap<>();
|
private final Map<UUID, FloodgatePlayer> players = new ConcurrentHashMap<>();
|
||||||
private final Cache<UUID, FloodgatePlayer> pendingRemove =
|
private final Cache<UUID, FloodgatePlayer> pendingRemove =
|
||||||
CacheBuilder.newBuilder()
|
CacheBuilder.newBuilder()
|
||||||
.expireAfterWrite(20, TimeUnit.SECONDS)
|
.expireAfterWrite(20, TimeUnit.SECONDS)
|
||||||
.build();
|
.build();
|
||||||
|
|
||||||
private final PluginMessageManager pluginMessageManager;
|
@Inject private PluginMessageManager pluginMessageManager;
|
||||||
private final FloodgateConfigHolder configHolder;
|
@Inject private FloodgateConfig config;
|
||||||
private final FloodgateLogger logger;
|
@Inject private HttpClient httpClient;
|
||||||
|
@Inject private FloodgateLogger logger;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String getPlayerPrefix() {
|
public String getPlayerPrefix() {
|
||||||
return configHolder.get().getUsernamePrefix();
|
return config.getUsernamePrefix();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -148,7 +148,7 @@ public class SimpleFloodgateApi implements FloodgateApi {
|
|||||||
return Utils.failedFuture(new IllegalStateException("Received an invalid gamertag"));
|
return Utils.failedFuture(new IllegalStateException("Received an invalid gamertag"));
|
||||||
}
|
}
|
||||||
|
|
||||||
return HttpUtils.asyncGet(Constants.GET_XUID_URL + gamertag)
|
return httpClient.asyncGet(Constants.GET_XUID_URL + gamertag)
|
||||||
.thenApply(result -> {
|
.thenApply(result -> {
|
||||||
JsonObject response = result.getResponse();
|
JsonObject response = result.getResponse();
|
||||||
|
|
||||||
@@ -163,7 +163,7 @@ public class SimpleFloodgateApi implements FloodgateApi {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public CompletableFuture<String> getGamertagFor(long xuid) {
|
public CompletableFuture<String> getGamertagFor(long xuid) {
|
||||||
return HttpUtils.asyncGet(Constants.GET_GAMERTAG_URL + xuid)
|
return httpClient.asyncGet(Constants.GET_GAMERTAG_URL + xuid)
|
||||||
.thenApply(result -> {
|
.thenApply(result -> {
|
||||||
JsonObject response = result.getResponse();
|
JsonObject response = result.getResponse();
|
||||||
|
|
||||||
|
|||||||
@@ -49,10 +49,11 @@ import org.geysermc.floodgate.player.UserAudience;
|
|||||||
import org.geysermc.floodgate.player.audience.ProfileAudience;
|
import org.geysermc.floodgate.player.audience.ProfileAudience;
|
||||||
import org.geysermc.floodgate.player.audience.ProfileAudienceArgument;
|
import org.geysermc.floodgate.player.audience.ProfileAudienceArgument;
|
||||||
import org.geysermc.floodgate.util.Constants;
|
import org.geysermc.floodgate.util.Constants;
|
||||||
import org.geysermc.floodgate.util.HttpUtils;
|
import org.geysermc.floodgate.util.HttpClient;
|
||||||
|
|
||||||
public class WhitelistCommand implements FloodgateCommand {
|
public class WhitelistCommand implements FloodgateCommand {
|
||||||
@Inject private FloodgateConfig config;
|
@Inject private FloodgateConfig config;
|
||||||
|
@Inject private HttpClient httpClient;
|
||||||
@Inject private FloodgateLogger logger;
|
@Inject private FloodgateLogger logger;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -128,7 +129,7 @@ public class WhitelistCommand implements FloodgateCommand {
|
|||||||
final String strippedName = name;
|
final String strippedName = name;
|
||||||
|
|
||||||
// We need to get the UUID of the player if it's not manually specified
|
// We need to get the UUID of the player if it's not manually specified
|
||||||
HttpUtils.asyncGet(Constants.GET_XUID_URL + name)
|
httpClient.asyncGet(Constants.GET_XUID_URL + name)
|
||||||
.whenComplete((result, error) -> {
|
.whenComplete((result, error) -> {
|
||||||
if (error != null) {
|
if (error != null) {
|
||||||
sender.sendMessage(Message.API_UNAVAILABLE);
|
sender.sendMessage(Message.API_UNAVAILABLE);
|
||||||
|
|||||||
@@ -29,20 +29,40 @@ import static org.geysermc.floodgate.util.Constants.COLOR_CHAR;
|
|||||||
|
|
||||||
import cloud.commandframework.context.CommandContext;
|
import cloud.commandframework.context.CommandContext;
|
||||||
import com.google.gson.JsonElement;
|
import com.google.gson.JsonElement;
|
||||||
|
import com.google.inject.Inject;
|
||||||
import it.unimi.dsi.fastutil.Pair;
|
import it.unimi.dsi.fastutil.Pair;
|
||||||
import java.util.concurrent.CompletableFuture;
|
import java.util.concurrent.CompletableFuture;
|
||||||
import java.util.concurrent.atomic.AtomicInteger;
|
import java.util.concurrent.atomic.AtomicInteger;
|
||||||
import java.util.function.BooleanSupplier;
|
import java.util.function.BooleanSupplier;
|
||||||
|
import org.geysermc.floodgate.command.util.Permission;
|
||||||
|
import org.geysermc.floodgate.platform.command.FloodgateSubCommand;
|
||||||
import org.geysermc.floodgate.player.UserAudience;
|
import org.geysermc.floodgate.player.UserAudience;
|
||||||
import org.geysermc.floodgate.util.Constants;
|
import org.geysermc.floodgate.util.Constants;
|
||||||
import org.geysermc.floodgate.util.HttpUtils;
|
import org.geysermc.floodgate.util.HttpClient;
|
||||||
import org.geysermc.floodgate.util.HttpUtils.HttpResponse;
|
import org.geysermc.floodgate.util.HttpClient.HttpResponse;
|
||||||
import org.geysermc.floodgate.util.Utils;
|
import org.geysermc.floodgate.util.Utils;
|
||||||
|
|
||||||
final class FirewallCheckSubcommand {
|
final class FirewallCheckSubcommand extends FloodgateSubCommand {
|
||||||
private FirewallCheckSubcommand() {}
|
@Inject
|
||||||
|
private HttpClient httpClient;
|
||||||
|
|
||||||
static void executeFirewall(CommandContext<UserAudience> context) {
|
@Override
|
||||||
|
public String name() {
|
||||||
|
return "firewall";
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String description() {
|
||||||
|
return "Check if your outgoing firewall allows Floodgate to work properly";
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Permission permission() {
|
||||||
|
return Permission.COMMAND_MAIN_FIREWALL;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void execute(CommandContext<UserAudience> context) {
|
||||||
UserAudience sender = context.getSender();
|
UserAudience sender = context.getSender();
|
||||||
executeChecks(
|
executeChecks(
|
||||||
globalApiCheck(sender)
|
globalApiCheck(sender)
|
||||||
@@ -54,12 +74,12 @@ final class FirewallCheckSubcommand {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static BooleanSupplier globalApiCheck(UserAudience sender) {
|
private BooleanSupplier globalApiCheck(UserAudience sender) {
|
||||||
return executeFirewallText(
|
return executeFirewallText(
|
||||||
sender, "global api",
|
sender, "global api",
|
||||||
() -> {
|
() -> {
|
||||||
HttpResponse<JsonElement> response =
|
HttpResponse<JsonElement> response =
|
||||||
HttpUtils.get(Constants.HEALTH_URL, JsonElement.class);
|
httpClient.get(Constants.HEALTH_URL, JsonElement.class);
|
||||||
|
|
||||||
if (!response.isCodeOk()) {
|
if (!response.isCodeOk()) {
|
||||||
throw new IllegalStateException(String.format(
|
throw new IllegalStateException(String.format(
|
||||||
@@ -70,7 +90,7 @@ final class FirewallCheckSubcommand {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
private static BooleanSupplier executeFirewallText(
|
private BooleanSupplier executeFirewallText(
|
||||||
UserAudience sender, String name, Runnable runnable) {
|
UserAudience sender, String name, Runnable runnable) {
|
||||||
return () -> {
|
return () -> {
|
||||||
sender.sendMessage(COLOR_CHAR + "eTesting " + name + "...");
|
sender.sendMessage(COLOR_CHAR + "eTesting " + name + "...");
|
||||||
@@ -86,9 +106,7 @@ final class FirewallCheckSubcommand {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
private static CompletableFuture<Pair<Integer, Integer>> executeChecks(
|
private CompletableFuture<Pair<Integer, Integer>> executeChecks(BooleanSupplier... checks) {
|
||||||
BooleanSupplier... checks) {
|
|
||||||
|
|
||||||
return CompletableFuture.supplyAsync(() -> {
|
return CompletableFuture.supplyAsync(() -> {
|
||||||
AtomicInteger okCount = new AtomicInteger();
|
AtomicInteger okCount = new AtomicInteger();
|
||||||
AtomicInteger failCount = new AtomicInteger();
|
AtomicInteger failCount = new AtomicInteger();
|
||||||
|
|||||||
@@ -33,13 +33,18 @@ import cloud.commandframework.Command.Builder;
|
|||||||
import cloud.commandframework.CommandManager;
|
import cloud.commandframework.CommandManager;
|
||||||
import cloud.commandframework.context.CommandContext;
|
import cloud.commandframework.context.CommandContext;
|
||||||
import java.util.Locale;
|
import java.util.Locale;
|
||||||
import java.util.function.Consumer;
|
|
||||||
import lombok.RequiredArgsConstructor;
|
|
||||||
import org.geysermc.floodgate.command.util.Permission;
|
import org.geysermc.floodgate.command.util.Permission;
|
||||||
import org.geysermc.floodgate.platform.command.FloodgateCommand;
|
import org.geysermc.floodgate.platform.command.FloodgateCommand;
|
||||||
|
import org.geysermc.floodgate.platform.command.FloodgateSubCommand;
|
||||||
|
import org.geysermc.floodgate.platform.command.SubCommands;
|
||||||
import org.geysermc.floodgate.player.UserAudience;
|
import org.geysermc.floodgate.player.UserAudience;
|
||||||
|
|
||||||
public final class MainCommand implements FloodgateCommand {
|
public final class MainCommand extends SubCommands implements FloodgateCommand {
|
||||||
|
public MainCommand() {
|
||||||
|
defineSubCommand(FirewallCheckSubcommand.class);
|
||||||
|
defineSubCommand(VersionSubcommand.class);
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Command<UserAudience> buildCommand(CommandManager<UserAudience> commandManager) {
|
public Command<UserAudience> buildCommand(CommandManager<UserAudience> commandManager) {
|
||||||
Builder<UserAudience> builder = commandManager.commandBuilder(
|
Builder<UserAudience> builder = commandManager.commandBuilder(
|
||||||
@@ -49,11 +54,11 @@ public final class MainCommand implements FloodgateCommand {
|
|||||||
.permission(Permission.COMMAND_MAIN.get())
|
.permission(Permission.COMMAND_MAIN.get())
|
||||||
.handler(this::execute);
|
.handler(this::execute);
|
||||||
|
|
||||||
for (SubCommand subCommand : SubCommand.VALUES) {
|
for (FloodgateSubCommand subCommand : subCommands()) {
|
||||||
commandManager.command(builder
|
commandManager.command(builder
|
||||||
.literal(subCommand.name().toLowerCase(Locale.ROOT), subCommand.description)
|
.literal(subCommand.name().toLowerCase(Locale.ROOT), subCommand.description())
|
||||||
.permission(subCommand.permission.get())
|
.permission(subCommand.permission().get())
|
||||||
.handler(subCommand.executor::accept)
|
.handler(subCommand::execute)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -65,27 +70,15 @@ public final class MainCommand implements FloodgateCommand {
|
|||||||
public void execute(CommandContext<UserAudience> context) {
|
public void execute(CommandContext<UserAudience> context) {
|
||||||
StringBuilder helpMessage = new StringBuilder("Available subcommands are:\n");
|
StringBuilder helpMessage = new StringBuilder("Available subcommands are:\n");
|
||||||
|
|
||||||
for (SubCommand subCommand : SubCommand.VALUES) {
|
for (FloodgateSubCommand subCommand : subCommands()) {
|
||||||
if (context.getSender().hasPermission(subCommand.permission.get())) {
|
if (context.getSender().hasPermission(subCommand.permission().get())) {
|
||||||
helpMessage.append('\n').append(COLOR_CHAR).append('b')
|
helpMessage.append('\n').append(COLOR_CHAR).append('b')
|
||||||
.append(subCommand.name().toLowerCase(Locale.ROOT))
|
.append(subCommand.name().toLowerCase(Locale.ROOT))
|
||||||
.append(COLOR_CHAR).append("f - ").append(COLOR_CHAR).append('7')
|
.append(COLOR_CHAR).append("f - ").append(COLOR_CHAR).append('7')
|
||||||
.append(subCommand.description);
|
.append(subCommand.description());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
context.getSender().sendMessage(helpMessage.toString());
|
context.getSender().sendMessage(helpMessage.toString());
|
||||||
}
|
}
|
||||||
|
|
||||||
@RequiredArgsConstructor
|
|
||||||
enum SubCommand {
|
|
||||||
FIREWALL("Check if your outgoing firewall allows Floodgate to work properly",
|
|
||||||
Permission.COMMAND_MAIN_FIREWALL, FirewallCheckSubcommand::executeFirewall);
|
|
||||||
|
|
||||||
static final SubCommand[] VALUES = values();
|
|
||||||
|
|
||||||
final String description;
|
|
||||||
final Permission permission;
|
|
||||||
final Consumer<CommandContext<UserAudience>> executor;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,129 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2019-2022 GeyserMC. http://geysermc.org
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
* of this software and associated documentation files (the "Software"), to deal
|
||||||
|
* in the Software without restriction, including without limitation the rights
|
||||||
|
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
* copies of the Software, and to permit persons to whom the Software is
|
||||||
|
* furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in
|
||||||
|
* all copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
|
* THE SOFTWARE.
|
||||||
|
*
|
||||||
|
* @author GeyserMC
|
||||||
|
* @link https://github.com/GeyserMC/Floodgate
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.geysermc.floodgate.command.main;
|
||||||
|
|
||||||
|
import static org.geysermc.floodgate.util.Constants.COLOR_CHAR;
|
||||||
|
|
||||||
|
import cloud.commandframework.context.CommandContext;
|
||||||
|
import com.google.gson.JsonElement;
|
||||||
|
import com.google.inject.Inject;
|
||||||
|
import org.geysermc.floodgate.api.logger.FloodgateLogger;
|
||||||
|
import org.geysermc.floodgate.command.WhitelistCommand.Message;
|
||||||
|
import org.geysermc.floodgate.command.util.Permission;
|
||||||
|
import org.geysermc.floodgate.platform.command.FloodgateSubCommand;
|
||||||
|
import org.geysermc.floodgate.player.UserAudience;
|
||||||
|
import org.geysermc.floodgate.util.Constants;
|
||||||
|
import org.geysermc.floodgate.util.HttpClient;
|
||||||
|
|
||||||
|
public class VersionSubcommand extends FloodgateSubCommand {
|
||||||
|
@Inject
|
||||||
|
private HttpClient httpClient;
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
private FloodgateLogger logger;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String name() {
|
||||||
|
return "version";
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String description() {
|
||||||
|
return "Displays version information about Floodgate";
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Permission permission() {
|
||||||
|
return Permission.COMMAND_MAIN_VERSION;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void execute(CommandContext<UserAudience> context) {
|
||||||
|
UserAudience sender = context.getSender();
|
||||||
|
sender.sendMessage(String.format(
|
||||||
|
COLOR_CHAR + "7You're currently on " + COLOR_CHAR + "b%s" +
|
||||||
|
COLOR_CHAR + "7 (branch: " + COLOR_CHAR + "b%s" + COLOR_CHAR + "7)\n" +
|
||||||
|
COLOR_CHAR + "eFetching latest build info...",
|
||||||
|
Constants.VERSION, Constants.GIT_BRANCH
|
||||||
|
));
|
||||||
|
|
||||||
|
String baseUrl = String.format(
|
||||||
|
"https://ci.opencollab.dev/job/GeyserMC/job/Floodgate/job/%s/lastSuccessfulBuild/",
|
||||||
|
Constants.GIT_BRANCH
|
||||||
|
);
|
||||||
|
|
||||||
|
httpClient.asyncGet(
|
||||||
|
baseUrl + "buildNumber",
|
||||||
|
JsonElement.class
|
||||||
|
).whenComplete((result, error) -> {
|
||||||
|
if (error != null) {
|
||||||
|
sender.sendMessage(COLOR_CHAR + "cCould not retrieve latest version info!");
|
||||||
|
error.printStackTrace();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
JsonElement response = result.getResponse();
|
||||||
|
|
||||||
|
logger.info(String.valueOf(response));
|
||||||
|
logger.info("{}", result.getHttpCode());
|
||||||
|
|
||||||
|
if (result.getHttpCode() == 404) {
|
||||||
|
sender.sendMessage(
|
||||||
|
COLOR_CHAR + "cGot a 404 (not found) while requesting the latest version." +
|
||||||
|
" Are you using a custom Floodgate version?"
|
||||||
|
);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!result.isCodeOk()) {
|
||||||
|
//todo make it more generic instead of using a Whitelist command strings
|
||||||
|
logger.error(
|
||||||
|
"Got an error from requesting the latest Floodgate version: {}",
|
||||||
|
response.toString()
|
||||||
|
);
|
||||||
|
sender.sendMessage(Message.UNEXPECTED_ERROR);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
int buildNumber = response.getAsInt();
|
||||||
|
|
||||||
|
if (buildNumber > Constants.BUILD_NUMBER) {
|
||||||
|
sender.sendMessage(String.format(
|
||||||
|
COLOR_CHAR + "7There is a newer version of Floodgate available!\n" +
|
||||||
|
COLOR_CHAR + "7You are " + COLOR_CHAR + "e%s " + COLOR_CHAR + "7builds behind.\n" +
|
||||||
|
COLOR_CHAR + "7Download the latest Floodgate version here: " + COLOR_CHAR + "b%s",
|
||||||
|
buildNumber - Constants.BUILD_NUMBER, baseUrl
|
||||||
|
));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (buildNumber == Constants.BUILD_NUMBER) {
|
||||||
|
sender.sendMessage(COLOR_CHAR + "aYou're running the latest version of Floodgate!");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
sender.sendMessage(COLOR_CHAR + "cCannot check version for custom Floodgate versions!");
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -31,6 +31,7 @@ import static org.geysermc.floodgate.command.util.PermissionDefault.TRUE;
|
|||||||
public enum Permission {
|
public enum Permission {
|
||||||
COMMAND_MAIN("floodgate.command.floodgate", TRUE),
|
COMMAND_MAIN("floodgate.command.floodgate", TRUE),
|
||||||
COMMAND_MAIN_FIREWALL(COMMAND_MAIN, "firewall", OP),
|
COMMAND_MAIN_FIREWALL(COMMAND_MAIN, "firewall", OP),
|
||||||
|
COMMAND_MAIN_VERSION(COMMAND_MAIN, "version", OP),
|
||||||
COMMAND_LINK("floodgate.command.linkaccount", TRUE),
|
COMMAND_LINK("floodgate.command.linkaccount", TRUE),
|
||||||
COMMAND_UNLINK("floodgate.command.unlinkaccount", TRUE),
|
COMMAND_UNLINK("floodgate.command.unlinkaccount", TRUE),
|
||||||
COMMAND_WHITELIST("floodgate.command.fwhitelist", OP),
|
COMMAND_WHITELIST("floodgate.command.fwhitelist", OP),
|
||||||
|
|||||||
@@ -35,21 +35,18 @@ import org.geysermc.configutils.ConfigUtilities;
|
|||||||
import org.geysermc.configutils.file.codec.PathFileCodec;
|
import org.geysermc.configutils.file.codec.PathFileCodec;
|
||||||
import org.geysermc.configutils.file.template.ResourceTemplateReader;
|
import org.geysermc.configutils.file.template.ResourceTemplateReader;
|
||||||
import org.geysermc.configutils.updater.change.Changes;
|
import org.geysermc.configutils.updater.change.Changes;
|
||||||
import org.geysermc.floodgate.api.logger.FloodgateLogger;
|
|
||||||
import org.geysermc.floodgate.crypto.FloodgateCipher;
|
import org.geysermc.floodgate.crypto.FloodgateCipher;
|
||||||
import org.geysermc.floodgate.crypto.KeyProducer;
|
import org.geysermc.floodgate.crypto.KeyProducer;
|
||||||
|
|
||||||
@Getter
|
@Getter
|
||||||
@RequiredArgsConstructor
|
@RequiredArgsConstructor
|
||||||
public final class ConfigLoader {
|
public final class ConfigLoader {
|
||||||
private final Path dataFolder;
|
private final Path dataDirectory;
|
||||||
private final Class<? extends FloodgateConfig> configClass;
|
private final Class<? extends FloodgateConfig> configClass;
|
||||||
|
|
||||||
private final KeyProducer keyProducer;
|
private final KeyProducer keyProducer;
|
||||||
private final FloodgateCipher cipher;
|
private final FloodgateCipher cipher;
|
||||||
|
|
||||||
private final FloodgateLogger logger;
|
|
||||||
|
|
||||||
@SuppressWarnings("unchecked")
|
@SuppressWarnings("unchecked")
|
||||||
public <T extends FloodgateConfig> T load() {
|
public <T extends FloodgateConfig> T load() {
|
||||||
String templateFile = "config.yml";
|
String templateFile = "config.yml";
|
||||||
@@ -65,7 +62,7 @@ public final class ConfigLoader {
|
|||||||
|
|
||||||
ConfigUtilities utilities =
|
ConfigUtilities utilities =
|
||||||
ConfigUtilities.builder()
|
ConfigUtilities.builder()
|
||||||
.fileCodec(PathFileCodec.of(dataFolder))
|
.fileCodec(PathFileCodec.of(dataDirectory))
|
||||||
.configFile("config.yml")
|
.configFile("config.yml")
|
||||||
.templateReader(ResourceTemplateReader.of(getClass()))
|
.templateReader(ResourceTemplateReader.of(getClass()))
|
||||||
.template(templateFile)
|
.template(templateFile)
|
||||||
@@ -100,21 +97,16 @@ public final class ConfigLoader {
|
|||||||
String decrypted = cipher.decryptToString(encrypted);
|
String decrypted = cipher.decryptToString(encrypted);
|
||||||
|
|
||||||
if (!test.equals(decrypted)) {
|
if (!test.equals(decrypted)) {
|
||||||
logger.error("Whoops, we tested the generated Floodgate keys but " +
|
throw new RuntimeException("Failed to decrypt test message.\n" +
|
||||||
"the decrypted test message doesn't match the original.\n" +
|
|
||||||
"Original message: " + test + "." +
|
"Original message: " + test + "." +
|
||||||
"Decrypted message: " + decrypted + ".\n" +
|
"Decrypted message: " + decrypted + ".\n" +
|
||||||
"The encrypted message itself: " + new String(encrypted)
|
"The encrypted message itself: " + new String(encrypted)
|
||||||
);
|
);
|
||||||
throw new RuntimeException(
|
|
||||||
"Tested the generated public and private key but, " +
|
|
||||||
"the decrypted message doesn't match the original!"
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Files.write(keyPath, key.getEncoded());
|
Files.write(keyPath, key.getEncoded());
|
||||||
} catch (Exception exception) {
|
} catch (Exception exception) {
|
||||||
logger.error("Error while creating key", exception);
|
throw new RuntimeException("Error while creating key", exception);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -52,7 +52,9 @@ public class FloodgateConfig implements GenericPostInitializeCallback<ConfigLoad
|
|||||||
private boolean debug;
|
private boolean debug;
|
||||||
private int configVersion;
|
private int configVersion;
|
||||||
|
|
||||||
|
|
||||||
private Key key;
|
private Key key;
|
||||||
|
private String rawUsernamePrefix;
|
||||||
|
|
||||||
public boolean isProxy() {
|
public boolean isProxy() {
|
||||||
return this instanceof ProxyFloodgateConfig;
|
return this instanceof ProxyFloodgateConfig;
|
||||||
@@ -60,7 +62,7 @@ public class FloodgateConfig implements GenericPostInitializeCallback<ConfigLoad
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public CallbackResult postInitialize(ConfigLoader loader) {
|
public CallbackResult postInitialize(ConfigLoader loader) {
|
||||||
Path keyPath = loader.getDataFolder().resolve(getKeyFileName());
|
Path keyPath = loader.getDataDirectory().resolve(getKeyFileName());
|
||||||
|
|
||||||
// don't assume that the key always exists with the existence of a config
|
// don't assume that the key always exists with the existence of a config
|
||||||
if (!Files.exists(keyPath)) {
|
if (!Files.exists(keyPath)) {
|
||||||
@@ -74,6 +76,14 @@ public class FloodgateConfig implements GenericPostInitializeCallback<ConfigLoad
|
|||||||
} catch (IOException exception) {
|
} catch (IOException exception) {
|
||||||
return CallbackResult.failed(exception.getMessage());
|
return CallbackResult.failed(exception.getMessage());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
rawUsernamePrefix = usernamePrefix;
|
||||||
|
|
||||||
|
// Java usernames can't be longer than 16 chars
|
||||||
|
if (usernamePrefix.length() >= 16) {
|
||||||
|
usernamePrefix = ".";
|
||||||
|
}
|
||||||
|
|
||||||
return CallbackResult.ok();
|
return CallbackResult.ok();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,63 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2019-2022 GeyserMC. http://geysermc.org
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
* of this software and associated documentation files (the "Software"), to deal
|
||||||
|
* in the Software without restriction, including without limitation the rights
|
||||||
|
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
* copies of the Software, and to permit persons to whom the Software is
|
||||||
|
* furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in
|
||||||
|
* all copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
|
* THE SOFTWARE.
|
||||||
|
*
|
||||||
|
* @author GeyserMC
|
||||||
|
* @link https://github.com/GeyserMC/Floodgate
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.geysermc.floodgate.event;
|
||||||
|
|
||||||
|
import com.google.inject.Singleton;
|
||||||
|
import java.util.function.BiConsumer;
|
||||||
|
import java.util.function.Consumer;
|
||||||
|
import org.checkerframework.checker.nullness.qual.NonNull;
|
||||||
|
import org.geysermc.event.PostOrder;
|
||||||
|
import org.geysermc.event.bus.impl.EventBusImpl;
|
||||||
|
import org.geysermc.event.subscribe.Subscribe;
|
||||||
|
import org.geysermc.event.subscribe.Subscriber;
|
||||||
|
import org.geysermc.floodgate.api.event.FloodgateEventBus;
|
||||||
|
import org.geysermc.floodgate.api.event.FloodgateSubscriber;
|
||||||
|
|
||||||
|
@Singleton
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
public final class EventBus extends EventBusImpl<Object, FloodgateSubscriber<?>>
|
||||||
|
implements FloodgateEventBus {
|
||||||
|
@Override
|
||||||
|
protected <H, T, B extends Subscriber<T>> B makeSubscription(
|
||||||
|
@NonNull Class<T> eventClass,
|
||||||
|
@NonNull Subscribe subscribe,
|
||||||
|
@NonNull H listener,
|
||||||
|
@NonNull BiConsumer<H, T> handler
|
||||||
|
) {
|
||||||
|
return (B) new EventSubscriber<>(
|
||||||
|
eventClass, subscribe.postOrder(), subscribe.ignoreCancelled(), listener, handler
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected <T, B extends Subscriber<T>> B makeSubscription(
|
||||||
|
@NonNull Class<T> eventClass,
|
||||||
|
@NonNull Consumer<T> handler,
|
||||||
|
@NonNull PostOrder postOrder
|
||||||
|
) {
|
||||||
|
return (B) new EventSubscriber<>(eventClass, handler, postOrder);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,53 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2019-2022 GeyserMC. http://geysermc.org
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
* of this software and associated documentation files (the "Software"), to deal
|
||||||
|
* in the Software without restriction, including without limitation the rights
|
||||||
|
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
* copies of the Software, and to permit persons to whom the Software is
|
||||||
|
* furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in
|
||||||
|
* all copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
|
* THE SOFTWARE.
|
||||||
|
*
|
||||||
|
* @author GeyserMC
|
||||||
|
* @link https://github.com/GeyserMC/Floodgate
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.geysermc.floodgate.event;
|
||||||
|
|
||||||
|
import java.util.function.BiConsumer;
|
||||||
|
import java.util.function.Consumer;
|
||||||
|
import org.checkerframework.checker.nullness.qual.NonNull;
|
||||||
|
import org.geysermc.event.PostOrder;
|
||||||
|
import org.geysermc.event.subscribe.impl.SubscriberImpl;
|
||||||
|
import org.geysermc.floodgate.api.event.FloodgateSubscriber;
|
||||||
|
|
||||||
|
public final class EventSubscriber<E> extends SubscriberImpl<E> implements FloodgateSubscriber<E> {
|
||||||
|
EventSubscriber(
|
||||||
|
@NonNull Class<E> eventClass,
|
||||||
|
@NonNull Consumer<E> handler,
|
||||||
|
@NonNull PostOrder postOrder
|
||||||
|
) {
|
||||||
|
super(eventClass, handler, postOrder);
|
||||||
|
}
|
||||||
|
|
||||||
|
<H> EventSubscriber(
|
||||||
|
Class<E> eventClass,
|
||||||
|
PostOrder postOrder,
|
||||||
|
boolean ignoreCancelled,
|
||||||
|
H handlerInstance,
|
||||||
|
BiConsumer<H, E> handler
|
||||||
|
) {
|
||||||
|
super(eventClass, postOrder, ignoreCancelled, handlerInstance, handler);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,29 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2019-2022 GeyserMC. http://geysermc.org
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
* of this software and associated documentation files (the "Software"), to deal
|
||||||
|
* in the Software without restriction, including without limitation the rights
|
||||||
|
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
* copies of the Software, and to permit persons to whom the Software is
|
||||||
|
* furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in
|
||||||
|
* all copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
|
* THE SOFTWARE.
|
||||||
|
*
|
||||||
|
* @author GeyserMC
|
||||||
|
* @link https://github.com/GeyserMC/Floodgate
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.geysermc.floodgate.event.lifecycle;
|
||||||
|
|
||||||
|
public class PostEnableEvent {
|
||||||
|
}
|
||||||
@@ -0,0 +1,29 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2019-2022 GeyserMC. http://geysermc.org
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
* of this software and associated documentation files (the "Software"), to deal
|
||||||
|
* in the Software without restriction, including without limitation the rights
|
||||||
|
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
* copies of the Software, and to permit persons to whom the Software is
|
||||||
|
* furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in
|
||||||
|
* all copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
|
* THE SOFTWARE.
|
||||||
|
*
|
||||||
|
* @author GeyserMC
|
||||||
|
* @link https://github.com/GeyserMC/Floodgate
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.geysermc.floodgate.event.lifecycle;
|
||||||
|
|
||||||
|
public class ShutdownEvent {
|
||||||
|
}
|
||||||
@@ -0,0 +1,67 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2019-2022 GeyserMC. http://geysermc.org
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
* of this software and associated documentation files (the "Software"), to deal
|
||||||
|
* in the Software without restriction, including without limitation the rights
|
||||||
|
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
* copies of the Software, and to permit persons to whom the Software is
|
||||||
|
* furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in
|
||||||
|
* all copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
|
* THE SOFTWARE.
|
||||||
|
*
|
||||||
|
* @author GeyserMC
|
||||||
|
* @link https://github.com/GeyserMC/Floodgate
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.geysermc.floodgate.event.skin;
|
||||||
|
|
||||||
|
import java.util.Objects;
|
||||||
|
import org.checkerframework.checker.nullness.qual.NonNull;
|
||||||
|
import org.checkerframework.checker.nullness.qual.Nullable;
|
||||||
|
import org.geysermc.event.util.AbstractCancellable;
|
||||||
|
import org.geysermc.floodgate.api.event.skin.SkinApplyEvent;
|
||||||
|
import org.geysermc.floodgate.api.player.FloodgatePlayer;
|
||||||
|
|
||||||
|
public class SkinApplyEventImpl extends AbstractCancellable implements SkinApplyEvent {
|
||||||
|
private final FloodgatePlayer player;
|
||||||
|
private final SkinData currentSkin;
|
||||||
|
private SkinData newSkin;
|
||||||
|
|
||||||
|
public SkinApplyEventImpl(
|
||||||
|
@NonNull FloodgatePlayer player,
|
||||||
|
@Nullable SkinData currentSkin,
|
||||||
|
@NonNull SkinData newSkin
|
||||||
|
) {
|
||||||
|
this.player = Objects.requireNonNull(player);
|
||||||
|
this.currentSkin = currentSkin;
|
||||||
|
this.newSkin = Objects.requireNonNull(newSkin);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public @NonNull FloodgatePlayer player() {
|
||||||
|
return player;
|
||||||
|
}
|
||||||
|
|
||||||
|
public @Nullable SkinData currentSkin() {
|
||||||
|
return currentSkin;
|
||||||
|
}
|
||||||
|
|
||||||
|
public @NonNull SkinData newSkin() {
|
||||||
|
return newSkin;
|
||||||
|
}
|
||||||
|
|
||||||
|
public SkinApplyEventImpl newSkin(@NonNull SkinData skinData) {
|
||||||
|
this.newSkin = Objects.requireNonNull(skinData);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,38 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2019-2022 GeyserMC. http://geysermc.org
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
* of this software and associated documentation files (the "Software"), to deal
|
||||||
|
* in the Software without restriction, including without limitation the rights
|
||||||
|
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
* copies of the Software, and to permit persons to whom the Software is
|
||||||
|
* furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in
|
||||||
|
* all copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
|
* THE SOFTWARE.
|
||||||
|
*
|
||||||
|
* @author GeyserMC
|
||||||
|
* @link https://github.com/GeyserMC/Floodgate
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.geysermc.floodgate.event.util;
|
||||||
|
|
||||||
|
import com.google.inject.TypeLiteral;
|
||||||
|
import com.google.inject.matcher.AbstractMatcher;
|
||||||
|
import org.geysermc.event.Listener;
|
||||||
|
|
||||||
|
public class ListenerAnnotationMatcher extends AbstractMatcher<TypeLiteral<?>> {
|
||||||
|
@Override
|
||||||
|
public boolean matches(TypeLiteral<?> typeLiteral) {
|
||||||
|
Class<?> rawType = typeLiteral.getRawType();
|
||||||
|
return rawType.isAnnotationPresent(Listener.class);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -26,18 +26,17 @@
|
|||||||
package org.geysermc.floodgate.inject;
|
package org.geysermc.floodgate.inject;
|
||||||
|
|
||||||
import io.netty.channel.Channel;
|
import io.netty.channel.Channel;
|
||||||
|
import java.util.Collections;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.HashSet;
|
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
import lombok.AccessLevel;
|
import java.util.WeakHashMap;
|
||||||
import lombok.Getter;
|
|
||||||
import org.geysermc.floodgate.api.inject.InjectorAddon;
|
import org.geysermc.floodgate.api.inject.InjectorAddon;
|
||||||
import org.geysermc.floodgate.api.inject.PlatformInjector;
|
import org.geysermc.floodgate.api.inject.PlatformInjector;
|
||||||
|
|
||||||
public abstract class CommonPlatformInjector implements PlatformInjector {
|
public abstract class CommonPlatformInjector implements PlatformInjector {
|
||||||
@Getter(AccessLevel.PROTECTED)
|
private final Set<Channel> injectedClients =
|
||||||
private final Set<Channel> injectedClients = new HashSet<>();
|
Collections.synchronizedSet(Collections.newSetFromMap(new WeakHashMap<>()));
|
||||||
|
|
||||||
private final Map<Class<?>, InjectorAddon> addons = new HashMap<>();
|
private final Map<Class<?>, InjectorAddon> addons = new HashMap<>();
|
||||||
|
|
||||||
@@ -49,6 +48,10 @@ public abstract class CommonPlatformInjector implements PlatformInjector {
|
|||||||
return injectedClients.remove(channel);
|
return injectedClients.remove(channel);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Set<Channel> injectedClients() {
|
||||||
|
return injectedClients;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean addAddon(InjectorAddon addon) {
|
public boolean addAddon(InjectorAddon addon) {
|
||||||
return addons.putIfAbsent(addon.getClass(), addon) == null;
|
return addons.putIfAbsent(addon.getClass(), addon) == null;
|
||||||
|
|||||||
@@ -34,6 +34,8 @@ import java.util.concurrent.ExecutorService;
|
|||||||
import java.util.concurrent.Executors;
|
import java.util.concurrent.Executors;
|
||||||
import lombok.AccessLevel;
|
import lombok.AccessLevel;
|
||||||
import lombok.Getter;
|
import lombok.Getter;
|
||||||
|
import org.geysermc.event.Listener;
|
||||||
|
import org.geysermc.event.subscribe.Subscribe;
|
||||||
import org.geysermc.floodgate.api.FloodgateApi;
|
import org.geysermc.floodgate.api.FloodgateApi;
|
||||||
import org.geysermc.floodgate.api.link.LinkRequest;
|
import org.geysermc.floodgate.api.link.LinkRequest;
|
||||||
import org.geysermc.floodgate.api.link.PlayerLink;
|
import org.geysermc.floodgate.api.link.PlayerLink;
|
||||||
@@ -41,11 +43,13 @@ import org.geysermc.floodgate.api.logger.FloodgateLogger;
|
|||||||
import org.geysermc.floodgate.config.FloodgateConfig;
|
import org.geysermc.floodgate.config.FloodgateConfig;
|
||||||
import org.geysermc.floodgate.database.config.DatabaseConfig;
|
import org.geysermc.floodgate.database.config.DatabaseConfig;
|
||||||
import org.geysermc.floodgate.database.config.DatabaseConfigLoader;
|
import org.geysermc.floodgate.database.config.DatabaseConfigLoader;
|
||||||
|
import org.geysermc.floodgate.event.lifecycle.ShutdownEvent;
|
||||||
import org.geysermc.floodgate.util.InjectorHolder;
|
import org.geysermc.floodgate.util.InjectorHolder;
|
||||||
|
|
||||||
|
@Listener
|
||||||
public abstract class CommonPlayerLink implements PlayerLink {
|
public abstract class CommonPlayerLink implements PlayerLink {
|
||||||
@Getter(AccessLevel.PROTECTED)
|
@Getter(AccessLevel.PROTECTED)
|
||||||
private final ExecutorService executorService = Executors.newFixedThreadPool(11);
|
private final ExecutorService executorService = Executors.newCachedThreadPool();
|
||||||
|
|
||||||
@Getter private boolean enabled;
|
@Getter private boolean enabled;
|
||||||
@Getter private boolean allowLinking;
|
@Getter private boolean allowLinking;
|
||||||
@@ -102,4 +106,9 @@ public abstract class CommonPlayerLink implements PlayerLink {
|
|||||||
public void stop() {
|
public void stop() {
|
||||||
executorService.shutdown();
|
executorService.shutdown();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Subscribe
|
||||||
|
public void onShutdown(ShutdownEvent ignored) {
|
||||||
|
stop();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -29,19 +29,23 @@ import static org.geysermc.floodgate.util.Constants.GET_BEDROCK_LINK;
|
|||||||
|
|
||||||
import com.google.gson.JsonElement;
|
import com.google.gson.JsonElement;
|
||||||
import com.google.gson.JsonObject;
|
import com.google.gson.JsonObject;
|
||||||
|
import com.google.inject.Inject;
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
import java.util.concurrent.CompletableFuture;
|
import java.util.concurrent.CompletableFuture;
|
||||||
import lombok.Getter;
|
import lombok.Getter;
|
||||||
import org.checkerframework.checker.nullness.qual.NonNull;
|
import org.checkerframework.checker.nullness.qual.NonNull;
|
||||||
import org.geysermc.floodgate.api.link.LinkRequestResult;
|
import org.geysermc.floodgate.api.link.LinkRequestResult;
|
||||||
import org.geysermc.floodgate.api.link.PlayerLink;
|
import org.geysermc.floodgate.api.link.PlayerLink;
|
||||||
import org.geysermc.floodgate.util.HttpUtils;
|
import org.geysermc.floodgate.util.HttpClient;
|
||||||
import org.geysermc.floodgate.util.HttpUtils.DefaultHttpResponse;
|
import org.geysermc.floodgate.util.HttpClient.DefaultHttpResponse;
|
||||||
import org.geysermc.floodgate.util.LinkedPlayer;
|
import org.geysermc.floodgate.util.LinkedPlayer;
|
||||||
import org.geysermc.floodgate.util.Utils;
|
import org.geysermc.floodgate.util.Utils;
|
||||||
|
|
||||||
@Getter
|
@Getter
|
||||||
public class GlobalPlayerLinking extends CommonPlayerLink {
|
public class GlobalPlayerLinking extends CommonPlayerLink {
|
||||||
|
@Inject
|
||||||
|
private HttpClient httpClient;
|
||||||
|
|
||||||
private PlayerLink databaseImpl;
|
private PlayerLink databaseImpl;
|
||||||
|
|
||||||
public void setDatabaseImpl(PlayerLink databaseImpl) {
|
public void setDatabaseImpl(PlayerLink databaseImpl) {
|
||||||
@@ -94,7 +98,7 @@ public class GlobalPlayerLinking extends CommonPlayerLink {
|
|||||||
return CompletableFuture.supplyAsync(
|
return CompletableFuture.supplyAsync(
|
||||||
() -> {
|
() -> {
|
||||||
DefaultHttpResponse response =
|
DefaultHttpResponse response =
|
||||||
HttpUtils.get(GET_BEDROCK_LINK + bedrockId.getLeastSignificantBits());
|
httpClient.get(GET_BEDROCK_LINK + bedrockId.getLeastSignificantBits());
|
||||||
|
|
||||||
// either the global api is down or it failed to return link
|
// either the global api is down or it failed to return link
|
||||||
if (!response.isCodeOk()) {
|
if (!response.isCodeOk()) {
|
||||||
@@ -144,7 +148,7 @@ public class GlobalPlayerLinking extends CommonPlayerLink {
|
|||||||
return CompletableFuture.supplyAsync(
|
return CompletableFuture.supplyAsync(
|
||||||
() -> {
|
() -> {
|
||||||
DefaultHttpResponse response =
|
DefaultHttpResponse response =
|
||||||
HttpUtils.get(GET_BEDROCK_LINK + bedrockId.getLeastSignificantBits());
|
httpClient.get(GET_BEDROCK_LINK + bedrockId.getLeastSignificantBits());
|
||||||
|
|
||||||
if (!response.isCodeOk()) {
|
if (!response.isCodeOk()) {
|
||||||
getLogger().error(
|
getLogger().error(
|
||||||
|
|||||||
@@ -32,6 +32,7 @@ import com.google.gson.JsonObject;
|
|||||||
import com.google.inject.Inject;
|
import com.google.inject.Inject;
|
||||||
import com.google.inject.Injector;
|
import com.google.inject.Injector;
|
||||||
import com.google.inject.Singleton;
|
import com.google.inject.Singleton;
|
||||||
|
import com.google.inject.name.Named;
|
||||||
import com.google.inject.name.Names;
|
import com.google.inject.name.Names;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
@@ -42,18 +43,23 @@ import java.nio.file.Files;
|
|||||||
import java.nio.file.Path;
|
import java.nio.file.Path;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
import javax.annotation.Nonnull;
|
import java.util.stream.Stream;
|
||||||
import javax.inject.Named;
|
import org.checkerframework.checker.nullness.qual.NonNull;
|
||||||
|
import org.geysermc.event.Listener;
|
||||||
|
import org.geysermc.event.subscribe.Subscribe;
|
||||||
import org.geysermc.floodgate.api.link.PlayerLink;
|
import org.geysermc.floodgate.api.link.PlayerLink;
|
||||||
import org.geysermc.floodgate.api.logger.FloodgateLogger;
|
import org.geysermc.floodgate.api.logger.FloodgateLogger;
|
||||||
import org.geysermc.floodgate.config.FloodgateConfig;
|
import org.geysermc.floodgate.config.FloodgateConfig;
|
||||||
|
import org.geysermc.floodgate.config.FloodgateConfig.PlayerLinkConfig;
|
||||||
|
import org.geysermc.floodgate.event.lifecycle.ShutdownEvent;
|
||||||
import org.geysermc.floodgate.util.Constants;
|
import org.geysermc.floodgate.util.Constants;
|
||||||
import org.geysermc.floodgate.util.InjectorHolder;
|
import org.geysermc.floodgate.util.InjectorHolder;
|
||||||
import org.geysermc.floodgate.util.Utils;
|
import org.geysermc.floodgate.util.Utils;
|
||||||
|
|
||||||
|
@Listener
|
||||||
@Singleton
|
@Singleton
|
||||||
@SuppressWarnings("unchecked")
|
@SuppressWarnings("unchecked")
|
||||||
public final class PlayerLinkLoader {
|
public final class PlayerLinkHolder {
|
||||||
@Inject private Injector injector;
|
@Inject private Injector injector;
|
||||||
@Inject private FloodgateConfig config;
|
@Inject private FloodgateConfig config;
|
||||||
@Inject private FloodgateLogger logger;
|
@Inject private FloodgateLogger logger;
|
||||||
@@ -62,30 +68,38 @@ public final class PlayerLinkLoader {
|
|||||||
@Named("dataDirectory")
|
@Named("dataDirectory")
|
||||||
private Path dataDirectory;
|
private Path dataDirectory;
|
||||||
|
|
||||||
@Nonnull
|
private URLClassLoader classLoader;
|
||||||
|
private PlayerLink instance;
|
||||||
|
|
||||||
|
@NonNull
|
||||||
public PlayerLink load() {
|
public PlayerLink load() {
|
||||||
|
if (instance != null) {
|
||||||
|
return instance;
|
||||||
|
}
|
||||||
|
|
||||||
if (config == null) {
|
if (config == null) {
|
||||||
throw new IllegalStateException("Config cannot be null!");
|
throw new IllegalStateException("Config cannot be null!");
|
||||||
}
|
}
|
||||||
|
|
||||||
FloodgateConfig.PlayerLinkConfig lConfig = config.getPlayerLink();
|
PlayerLinkConfig linkConfig = config.getPlayerLink();
|
||||||
if (!lConfig.isEnabled()) {
|
if (!linkConfig.isEnabled()) {
|
||||||
return new DisabledPlayerLink();
|
return new DisabledPlayerLink();
|
||||||
}
|
}
|
||||||
|
|
||||||
List<Path> files;
|
List<Path> files;
|
||||||
try {
|
try (Stream<Path> list = Files.list(dataDirectory)) {
|
||||||
files = Files.list(dataDirectory)
|
files = list
|
||||||
.filter(path -> Files.isRegularFile(path) && path.toString().endsWith("jar"))
|
.filter(path -> Files.isRegularFile(path) && path.toString().endsWith(".jar"))
|
||||||
.collect(Collectors.toList());
|
.collect(Collectors.toList());
|
||||||
} catch (IOException exception) {
|
} catch (IOException exception) {
|
||||||
logger.error("Failed to list possible database implementations", exception);
|
logger.error("Failed to list possible database implementations", exception);
|
||||||
return new DisabledPlayerLink();
|
return new DisabledPlayerLink();
|
||||||
}
|
}
|
||||||
|
|
||||||
// we can skip the rest if global linking is enabled and no database implementations has been
|
// we can skip the rest if global linking is enabled and no database implementations has
|
||||||
// found, or when global linking is enabled and own player linking is disabled.
|
// been found, or when global linking is enabled and own player linking is disabled.
|
||||||
if (lConfig.isEnableGlobalLinking() && (files.isEmpty() || !lConfig.isEnableOwnLinking())) {
|
if (linkConfig.isEnableGlobalLinking() &&
|
||||||
|
(files.isEmpty() || !linkConfig.isEnableOwnLinking())) {
|
||||||
return injector.getInstance(GlobalPlayerLinking.class);
|
return injector.getInstance(GlobalPlayerLinking.class);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -100,7 +114,7 @@ public final class PlayerLinkLoader {
|
|||||||
// We only want to load one database implementation
|
// We only want to load one database implementation
|
||||||
if (files.size() > 1) {
|
if (files.size() > 1) {
|
||||||
boolean found = false;
|
boolean found = false;
|
||||||
databaseName = lConfig.getType();
|
databaseName = linkConfig.getType();
|
||||||
|
|
||||||
String expectedName = "floodgate-" + databaseName + "-database.jar";
|
String expectedName = "floodgate-" + databaseName + "-database.jar";
|
||||||
for (Path path : files) {
|
for (Path path : files) {
|
||||||
@@ -111,14 +125,18 @@ public final class PlayerLinkLoader {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (!found) {
|
if (!found) {
|
||||||
logger.error("Failed to find an implementation for type: {}", lConfig.getType());
|
logger.error(
|
||||||
|
"Failed to find an implementation for type: {}", linkConfig.getType()
|
||||||
|
);
|
||||||
return new DisabledPlayerLink();
|
return new DisabledPlayerLink();
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
String name = implementationPath.getFileName().toString();
|
String name = implementationPath.getFileName().toString();
|
||||||
if (!Utils.isValidDatabaseName(name)) {
|
if (!Utils.isValidDatabaseName(name)) {
|
||||||
logger.error("Found database {} but the name doesn't match {}",
|
logger.error(
|
||||||
name, Constants.DATABASE_NAME_FORMAT);
|
"Found database {} but the name doesn't match {}",
|
||||||
|
name, Constants.DATABASE_NAME_FORMAT
|
||||||
|
);
|
||||||
return new DisabledPlayerLink();
|
return new DisabledPlayerLink();
|
||||||
}
|
}
|
||||||
int firstSplit = name.indexOf('-') + 1;
|
int firstSplit = name.indexOf('-') + 1;
|
||||||
@@ -133,24 +151,22 @@ public final class PlayerLinkLoader {
|
|||||||
// we don't have a way to close this properly since we have no stop method and we have
|
// we don't have a way to close this properly since we have no stop method and we have
|
||||||
// to be able to load classes on the fly, but that doesn't matter anyway since Floodgate
|
// to be able to load classes on the fly, but that doesn't matter anyway since Floodgate
|
||||||
// doesn't support reloading
|
// doesn't support reloading
|
||||||
URLClassLoader classLoader = new URLClassLoader(
|
classLoader = new URLClassLoader(
|
||||||
new URL[]{pluginUrl},
|
new URL[]{pluginUrl},
|
||||||
PlayerLinkLoader.class.getClassLoader()
|
PlayerLinkHolder.class.getClassLoader()
|
||||||
);
|
);
|
||||||
|
|
||||||
String mainClassName;
|
String mainClassName;
|
||||||
JsonObject linkConfig;
|
JsonObject dbInitConfig;
|
||||||
|
|
||||||
try (InputStream linkConfigStream =
|
|
||||||
classLoader.getResourceAsStream("init.json")) {
|
|
||||||
|
|
||||||
|
try (InputStream linkConfigStream = classLoader.getResourceAsStream("init.json")) {
|
||||||
requireNonNull(linkConfigStream, "Implementation should have an init file");
|
requireNonNull(linkConfigStream, "Implementation should have an init file");
|
||||||
|
|
||||||
linkConfig = new Gson().fromJson(
|
dbInitConfig = new Gson().fromJson(
|
||||||
new InputStreamReader(linkConfigStream), JsonObject.class
|
new InputStreamReader(linkConfigStream), JsonObject.class
|
||||||
);
|
);
|
||||||
|
|
||||||
mainClassName = linkConfig.get("mainClass").getAsString();
|
mainClassName = dbInitConfig.get("mainClass").getAsString();
|
||||||
}
|
}
|
||||||
|
|
||||||
Class<? extends PlayerLink> mainClass =
|
Class<? extends PlayerLink> mainClass =
|
||||||
@@ -167,16 +183,16 @@ public final class PlayerLinkLoader {
|
|||||||
Names.named("databaseClassLoader")).toInstance(classLoader);
|
Names.named("databaseClassLoader")).toInstance(classLoader);
|
||||||
binder.bind(JsonObject.class)
|
binder.bind(JsonObject.class)
|
||||||
.annotatedWith(Names.named("databaseInitData"))
|
.annotatedWith(Names.named("databaseInitData"))
|
||||||
.toInstance(linkConfig);
|
.toInstance(dbInitConfig);
|
||||||
binder.bind(InjectorHolder.class)
|
binder.bind(InjectorHolder.class)
|
||||||
.toInstance(injectorHolder);
|
.toInstance(injectorHolder);
|
||||||
});
|
});
|
||||||
injectorHolder.set(linkInjector);
|
injectorHolder.set(linkInjector);
|
||||||
|
|
||||||
PlayerLink instance = linkInjector.getInstance(mainClass);
|
instance = linkInjector.getInstance(mainClass);
|
||||||
|
|
||||||
// we use our own internal PlayerLinking when global linking is enabled
|
// we use our own internal PlayerLinking when global linking is enabled
|
||||||
if (lConfig.isEnableGlobalLinking()) {
|
if (linkConfig.isEnableGlobalLinking()) {
|
||||||
GlobalPlayerLinking linking = linkInjector.getInstance(GlobalPlayerLinking.class);
|
GlobalPlayerLinking linking = linkInjector.getInstance(GlobalPlayerLinking.class);
|
||||||
linking.setDatabaseImpl(instance);
|
linking.setDatabaseImpl(instance);
|
||||||
linking.load();
|
linking.load();
|
||||||
@@ -186,8 +202,10 @@ public final class PlayerLinkLoader {
|
|||||||
return instance;
|
return instance;
|
||||||
}
|
}
|
||||||
} catch (ClassCastException exception) {
|
} catch (ClassCastException exception) {
|
||||||
logger.error("The database implementation ({}) doesn't extend the PlayerLink class!",
|
logger.error(
|
||||||
implementationPath.getFileName().toString(), exception);
|
"The database implementation ({}) doesn't extend the PlayerLink class!",
|
||||||
|
implementationPath.getFileName().toString(), exception
|
||||||
|
);
|
||||||
return new DisabledPlayerLink();
|
return new DisabledPlayerLink();
|
||||||
} catch (Exception exception) {
|
} catch (Exception exception) {
|
||||||
if (init) {
|
if (init) {
|
||||||
@@ -198,4 +216,10 @@ public final class PlayerLinkLoader {
|
|||||||
return new DisabledPlayerLink();
|
return new DisabledPlayerLink();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Subscribe
|
||||||
|
public void onShutdown(ShutdownEvent ignored) throws Exception {
|
||||||
|
instance.stop();
|
||||||
|
classLoader.close();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -27,17 +27,29 @@ package org.geysermc.floodgate.logger;
|
|||||||
|
|
||||||
import static org.geysermc.floodgate.util.MessageFormatter.format;
|
import static org.geysermc.floodgate.util.MessageFormatter.format;
|
||||||
|
|
||||||
|
import com.google.inject.Inject;
|
||||||
|
import com.google.inject.Singleton;
|
||||||
|
import com.google.inject.name.Named;
|
||||||
import java.util.logging.Level;
|
import java.util.logging.Level;
|
||||||
import java.util.logging.Logger;
|
import java.util.logging.Logger;
|
||||||
import lombok.RequiredArgsConstructor;
|
|
||||||
import org.geysermc.floodgate.api.logger.FloodgateLogger;
|
import org.geysermc.floodgate.api.logger.FloodgateLogger;
|
||||||
|
import org.geysermc.floodgate.config.FloodgateConfig;
|
||||||
import org.geysermc.floodgate.util.LanguageManager;
|
import org.geysermc.floodgate.util.LanguageManager;
|
||||||
|
|
||||||
@RequiredArgsConstructor
|
@Singleton
|
||||||
public final class JavaUtilFloodgateLogger implements FloodgateLogger {
|
public final class JavaUtilFloodgateLogger implements FloodgateLogger {
|
||||||
private final Logger logger;
|
@Inject
|
||||||
private final LanguageManager languageManager;
|
@Named("logger")
|
||||||
private Level originLevel;
|
private Logger logger;
|
||||||
|
private LanguageManager languageManager;
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
private void init(LanguageManager languageManager, FloodgateConfig config) {
|
||||||
|
this.languageManager = languageManager;
|
||||||
|
if (config.isDebug()) {
|
||||||
|
logger.setLevel(Level.ALL);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void error(String message, Object... args) {
|
public void error(String message, Object... args) {
|
||||||
@@ -74,19 +86,6 @@ public final class JavaUtilFloodgateLogger implements FloodgateLogger {
|
|||||||
logger.finer(format(message, args));
|
logger.finer(format(message, args));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public void enableDebug() {
|
|
||||||
originLevel = logger.getLevel();
|
|
||||||
logger.setLevel(Level.ALL);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void disableDebug() {
|
|
||||||
if (originLevel != null) {
|
|
||||||
logger.setLevel(originLevel);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean isDebug() {
|
public boolean isDebug() {
|
||||||
return logger.getLevel() == Level.ALL;
|
return logger.getLevel() == Level.ALL;
|
||||||
|
|||||||
@@ -23,25 +23,17 @@
|
|||||||
* @link https://github.com/GeyserMC/Floodgate
|
* @link https://github.com/GeyserMC/Floodgate
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package org.geysermc.floodgate.skin;
|
package org.geysermc.floodgate.module;
|
||||||
|
|
||||||
import com.google.gson.JsonObject;
|
import com.google.inject.AbstractModule;
|
||||||
import lombok.Getter;
|
import org.geysermc.floodgate.util.AutoBind;
|
||||||
import lombok.RequiredArgsConstructor;
|
import org.geysermc.floodgate.util.Utils;
|
||||||
|
|
||||||
@Getter
|
public class AutoBindModule extends AbstractModule {
|
||||||
@RequiredArgsConstructor
|
@Override
|
||||||
public class SkinData {
|
protected void configure() {
|
||||||
private final String value;
|
for (Class<?> clazz : Utils.getGeneratedClassesForAnnotation(AutoBind.class)) {
|
||||||
private final String signature;
|
bind(clazz).asEagerSingleton();
|
||||||
|
}
|
||||||
public static SkinData from(JsonObject data) {
|
|
||||||
if (data.has("signature") && !data.get("signature").isJsonNull()) {
|
|
||||||
return new SkinData(
|
|
||||||
data.get("value").getAsString(),
|
|
||||||
data.get("signature").getAsString()
|
|
||||||
);
|
|
||||||
}
|
|
||||||
return new SkinData(data.get("value").getAsString(), null);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -28,49 +28,105 @@ package org.geysermc.floodgate.module;
|
|||||||
import com.google.inject.AbstractModule;
|
import com.google.inject.AbstractModule;
|
||||||
import com.google.inject.Provides;
|
import com.google.inject.Provides;
|
||||||
import com.google.inject.Singleton;
|
import com.google.inject.Singleton;
|
||||||
|
import com.google.inject.TypeLiteral;
|
||||||
import com.google.inject.name.Named;
|
import com.google.inject.name.Named;
|
||||||
|
import com.google.inject.name.Names;
|
||||||
|
import com.google.inject.spi.InjectionListener;
|
||||||
|
import com.google.inject.spi.TypeEncounter;
|
||||||
|
import com.google.inject.spi.TypeListener;
|
||||||
import io.netty.util.AttributeKey;
|
import io.netty.util.AttributeKey;
|
||||||
import java.nio.file.Path;
|
import java.nio.file.Path;
|
||||||
|
import java.util.concurrent.ExecutorService;
|
||||||
|
import java.util.concurrent.Executors;
|
||||||
|
import java.util.concurrent.ScheduledExecutorService;
|
||||||
import lombok.RequiredArgsConstructor;
|
import lombok.RequiredArgsConstructor;
|
||||||
|
import org.geysermc.event.PostOrder;
|
||||||
import org.geysermc.floodgate.addon.data.HandshakeHandlersImpl;
|
import org.geysermc.floodgate.addon.data.HandshakeHandlersImpl;
|
||||||
import org.geysermc.floodgate.api.FloodgateApi;
|
import org.geysermc.floodgate.api.FloodgateApi;
|
||||||
import org.geysermc.floodgate.api.SimpleFloodgateApi;
|
import org.geysermc.floodgate.api.SimpleFloodgateApi;
|
||||||
|
import org.geysermc.floodgate.api.event.FloodgateEventBus;
|
||||||
import org.geysermc.floodgate.api.handshake.HandshakeHandlers;
|
import org.geysermc.floodgate.api.handshake.HandshakeHandlers;
|
||||||
import org.geysermc.floodgate.api.inject.PlatformInjector;
|
import org.geysermc.floodgate.api.inject.PlatformInjector;
|
||||||
|
import org.geysermc.floodgate.api.link.PlayerLink;
|
||||||
import org.geysermc.floodgate.api.logger.FloodgateLogger;
|
import org.geysermc.floodgate.api.logger.FloodgateLogger;
|
||||||
import org.geysermc.floodgate.api.packet.PacketHandlers;
|
import org.geysermc.floodgate.api.packet.PacketHandlers;
|
||||||
import org.geysermc.floodgate.api.player.FloodgatePlayer;
|
import org.geysermc.floodgate.api.player.FloodgatePlayer;
|
||||||
import org.geysermc.floodgate.config.ConfigLoader;
|
import org.geysermc.floodgate.config.ConfigLoader;
|
||||||
import org.geysermc.floodgate.config.FloodgateConfig;
|
import org.geysermc.floodgate.config.FloodgateConfig;
|
||||||
import org.geysermc.floodgate.config.FloodgateConfigHolder;
|
|
||||||
import org.geysermc.floodgate.crypto.AesCipher;
|
import org.geysermc.floodgate.crypto.AesCipher;
|
||||||
import org.geysermc.floodgate.crypto.AesKeyProducer;
|
import org.geysermc.floodgate.crypto.AesKeyProducer;
|
||||||
import org.geysermc.floodgate.crypto.Base64Topping;
|
import org.geysermc.floodgate.crypto.Base64Topping;
|
||||||
import org.geysermc.floodgate.crypto.FloodgateCipher;
|
import org.geysermc.floodgate.crypto.FloodgateCipher;
|
||||||
import org.geysermc.floodgate.crypto.KeyProducer;
|
import org.geysermc.floodgate.crypto.KeyProducer;
|
||||||
|
import org.geysermc.floodgate.event.EventBus;
|
||||||
|
import org.geysermc.floodgate.event.lifecycle.ShutdownEvent;
|
||||||
|
import org.geysermc.floodgate.event.util.ListenerAnnotationMatcher;
|
||||||
import org.geysermc.floodgate.inject.CommonPlatformInjector;
|
import org.geysermc.floodgate.inject.CommonPlatformInjector;
|
||||||
import org.geysermc.floodgate.news.NewsChecker;
|
import org.geysermc.floodgate.link.PlayerLinkHolder;
|
||||||
import org.geysermc.floodgate.packet.PacketHandlersImpl;
|
import org.geysermc.floodgate.packet.PacketHandlersImpl;
|
||||||
import org.geysermc.floodgate.platform.command.CommandUtil;
|
|
||||||
import org.geysermc.floodgate.player.FloodgateHandshakeHandler;
|
import org.geysermc.floodgate.player.FloodgateHandshakeHandler;
|
||||||
import org.geysermc.floodgate.pluginmessage.PluginMessageManager;
|
import org.geysermc.floodgate.pluginmessage.PluginMessageManager;
|
||||||
import org.geysermc.floodgate.skin.SkinApplier;
|
|
||||||
import org.geysermc.floodgate.skin.SkinUploadManager;
|
import org.geysermc.floodgate.skin.SkinUploadManager;
|
||||||
import org.geysermc.floodgate.util.Constants;
|
import org.geysermc.floodgate.util.Constants;
|
||||||
|
import org.geysermc.floodgate.util.HttpClient;
|
||||||
import org.geysermc.floodgate.util.LanguageManager;
|
import org.geysermc.floodgate.util.LanguageManager;
|
||||||
|
|
||||||
@RequiredArgsConstructor
|
@RequiredArgsConstructor
|
||||||
public class CommonModule extends AbstractModule {
|
public class CommonModule extends AbstractModule {
|
||||||
|
private final EventBus eventBus = new EventBus();
|
||||||
private final Path dataDirectory;
|
private final Path dataDirectory;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void configure() {
|
protected void configure() {
|
||||||
|
bind(EventBus.class).toInstance(eventBus);
|
||||||
|
bind(FloodgateEventBus.class).to(EventBus.class);
|
||||||
|
// register every class that has the Listener annotation
|
||||||
|
bindListener(new ListenerAnnotationMatcher(), new TypeListener() {
|
||||||
|
@Override
|
||||||
|
public <I> void hear(TypeLiteral<I> type, TypeEncounter<I> encounter) {
|
||||||
|
encounter.register((InjectionListener<I>) eventBus::register);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
ExecutorService commonPool = Executors.newCachedThreadPool();
|
||||||
|
ScheduledExecutorService commonScheduledPool = Executors.newSingleThreadScheduledExecutor();
|
||||||
|
|
||||||
|
eventBus.subscribe(ShutdownEvent.class, ignored -> {
|
||||||
|
commonPool.shutdown();
|
||||||
|
commonScheduledPool.shutdown();
|
||||||
|
}, PostOrder.LAST);
|
||||||
|
|
||||||
|
bind(ExecutorService.class)
|
||||||
|
.annotatedWith(Names.named("commonPool"))
|
||||||
|
.toInstance(commonPool);
|
||||||
|
bind(ScheduledExecutorService.class)
|
||||||
|
.annotatedWith(Names.named("commonScheduledPool"))
|
||||||
|
.toInstance(commonScheduledPool);
|
||||||
|
|
||||||
|
bind(HttpClient.class).in(Singleton.class);
|
||||||
|
|
||||||
bind(FloodgateApi.class).to(SimpleFloodgateApi.class);
|
bind(FloodgateApi.class).to(SimpleFloodgateApi.class);
|
||||||
bind(PlatformInjector.class).to(CommonPlatformInjector.class);
|
bind(PlatformInjector.class).to(CommonPlatformInjector.class);
|
||||||
|
|
||||||
bind(HandshakeHandlers.class).to(HandshakeHandlersImpl.class);
|
bind(HandshakeHandlers.class).to(HandshakeHandlersImpl.class);
|
||||||
|
bind(HandshakeHandlersImpl.class).in(Singleton.class);
|
||||||
|
|
||||||
bind(PacketHandlers.class).to(PacketHandlersImpl.class);
|
bind(PacketHandlers.class).to(PacketHandlersImpl.class);
|
||||||
bind(PacketHandlersImpl.class).asEagerSingleton();
|
bind(PacketHandlersImpl.class).asEagerSingleton();
|
||||||
|
|
||||||
|
install(new AutoBindModule());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Provides
|
||||||
|
@Singleton
|
||||||
|
public FloodgateConfig floodgateConfig(ConfigLoader configLoader) {
|
||||||
|
return configLoader.load();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Provides
|
||||||
|
@Singleton
|
||||||
|
public PlayerLink playerLink(PlayerLinkHolder linkLoader) {
|
||||||
|
return linkLoader.load();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Provides
|
@Provides
|
||||||
@@ -92,34 +148,13 @@ public class CommonModule extends AbstractModule {
|
|||||||
return dataDirectory;
|
return dataDirectory;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Provides
|
|
||||||
@Singleton
|
|
||||||
public FloodgateConfigHolder configHolder() {
|
|
||||||
return new FloodgateConfigHolder();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Provides
|
@Provides
|
||||||
@Singleton
|
@Singleton
|
||||||
public ConfigLoader configLoader(
|
public ConfigLoader configLoader(
|
||||||
@Named("configClass") Class<? extends FloodgateConfig> configClass,
|
@Named("configClass") Class<? extends FloodgateConfig> configClass,
|
||||||
KeyProducer producer,
|
KeyProducer producer,
|
||||||
FloodgateCipher cipher,
|
FloodgateCipher cipher) {
|
||||||
FloodgateLogger logger) {
|
return new ConfigLoader(dataDirectory, configClass, producer, cipher);
|
||||||
return new ConfigLoader(dataDirectory, configClass, producer, cipher, logger);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Provides
|
|
||||||
@Singleton
|
|
||||||
public LanguageManager languageLoader(
|
|
||||||
FloodgateConfigHolder configHolder,
|
|
||||||
FloodgateLogger logger) {
|
|
||||||
return new LanguageManager(configHolder, logger);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Provides
|
|
||||||
@Singleton
|
|
||||||
public HandshakeHandlersImpl handshakeHandlers() {
|
|
||||||
return new HandshakeHandlersImpl();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Provides
|
@Provides
|
||||||
@@ -128,13 +163,14 @@ public class CommonModule extends AbstractModule {
|
|||||||
HandshakeHandlersImpl handshakeHandlers,
|
HandshakeHandlersImpl handshakeHandlers,
|
||||||
SimpleFloodgateApi api,
|
SimpleFloodgateApi api,
|
||||||
FloodgateCipher cipher,
|
FloodgateCipher cipher,
|
||||||
FloodgateConfigHolder configHolder,
|
FloodgateConfig config,
|
||||||
SkinUploadManager skinUploadManager,
|
SkinUploadManager skinUploadManager,
|
||||||
@Named("playerAttribute") AttributeKey<FloodgatePlayer> playerAttribute,
|
@Named("playerAttribute") AttributeKey<FloodgatePlayer> playerAttribute,
|
||||||
FloodgateLogger logger) {
|
FloodgateLogger logger,
|
||||||
|
LanguageManager languageManager) {
|
||||||
|
|
||||||
return new FloodgateHandshakeHandler(handshakeHandlers, api, cipher, configHolder,
|
return new FloodgateHandshakeHandler(handshakeHandlers, api, cipher, config,
|
||||||
skinUploadManager, playerAttribute, logger);
|
skinUploadManager, playerAttribute, logger, languageManager);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Provides
|
@Provides
|
||||||
@@ -145,17 +181,16 @@ public class CommonModule extends AbstractModule {
|
|||||||
|
|
||||||
@Provides
|
@Provides
|
||||||
@Singleton
|
@Singleton
|
||||||
public SkinUploadManager skinUploadManager(
|
@Named("gitBranch")
|
||||||
FloodgateApi api,
|
public String gitBranch() {
|
||||||
SkinApplier skinApplier,
|
return Constants.GIT_BRANCH;
|
||||||
FloodgateLogger logger) {
|
|
||||||
return new SkinUploadManager(api, skinApplier, logger);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Provides
|
@Provides
|
||||||
@Singleton
|
@Singleton
|
||||||
public NewsChecker newsChecker(CommandUtil commandUtil, FloodgateLogger logger) {
|
@Named("buildNumber")
|
||||||
return new NewsChecker(commandUtil, logger, Constants.GIT_BRANCH, Constants.BUILD_NUMBER);
|
public int buildNumber() {
|
||||||
|
return Constants.BUILD_NUMBER;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Provides
|
@Provides
|
||||||
|
|||||||
@@ -31,12 +31,8 @@ import com.google.inject.name.Named;
|
|||||||
import java.nio.file.Path;
|
import java.nio.file.Path;
|
||||||
import org.geysermc.floodgate.api.ProxyFloodgateApi;
|
import org.geysermc.floodgate.api.ProxyFloodgateApi;
|
||||||
import org.geysermc.floodgate.api.SimpleFloodgateApi;
|
import org.geysermc.floodgate.api.SimpleFloodgateApi;
|
||||||
import org.geysermc.floodgate.api.logger.FloodgateLogger;
|
|
||||||
import org.geysermc.floodgate.config.FloodgateConfig;
|
import org.geysermc.floodgate.config.FloodgateConfig;
|
||||||
import org.geysermc.floodgate.config.FloodgateConfigHolder;
|
|
||||||
import org.geysermc.floodgate.config.ProxyFloodgateConfig;
|
import org.geysermc.floodgate.config.ProxyFloodgateConfig;
|
||||||
import org.geysermc.floodgate.crypto.FloodgateCipher;
|
|
||||||
import org.geysermc.floodgate.pluginmessage.PluginMessageManager;
|
|
||||||
|
|
||||||
public final class ProxyCommonModule extends CommonModule {
|
public final class ProxyCommonModule extends CommonModule {
|
||||||
public ProxyCommonModule(Path dataDirectory) {
|
public ProxyCommonModule(Path dataDirectory) {
|
||||||
@@ -46,7 +42,15 @@ public final class ProxyCommonModule extends CommonModule {
|
|||||||
@Override
|
@Override
|
||||||
protected void configure() {
|
protected void configure() {
|
||||||
super.configure();
|
super.configure();
|
||||||
|
|
||||||
bind(SimpleFloodgateApi.class).to(ProxyFloodgateApi.class);
|
bind(SimpleFloodgateApi.class).to(ProxyFloodgateApi.class);
|
||||||
|
bind(ProxyFloodgateApi.class).in(Singleton.class);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Provides
|
||||||
|
@Singleton
|
||||||
|
public ProxyFloodgateConfig proxyFloodgateConfig(FloodgateConfig config) {
|
||||||
|
return (ProxyFloodgateConfig) config;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Provides
|
@Provides
|
||||||
@@ -55,14 +59,4 @@ public final class ProxyCommonModule extends CommonModule {
|
|||||||
public Class<? extends FloodgateConfig> floodgateConfigClass() {
|
public Class<? extends FloodgateConfig> floodgateConfigClass() {
|
||||||
return ProxyFloodgateConfig.class;
|
return ProxyFloodgateConfig.class;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Provides
|
|
||||||
@Singleton
|
|
||||||
public ProxyFloodgateApi proxyFloodgateApi(
|
|
||||||
PluginMessageManager pluginMessageManager,
|
|
||||||
FloodgateConfigHolder configHolder,
|
|
||||||
FloodgateLogger logger,
|
|
||||||
FloodgateCipher cipher) {
|
|
||||||
return new ProxyFloodgateApi(pluginMessageManager, configHolder, logger, cipher);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -30,29 +30,23 @@ import com.google.inject.Singleton;
|
|||||||
import com.google.inject.name.Named;
|
import com.google.inject.name.Named;
|
||||||
import java.nio.file.Path;
|
import java.nio.file.Path;
|
||||||
import org.geysermc.floodgate.api.SimpleFloodgateApi;
|
import org.geysermc.floodgate.api.SimpleFloodgateApi;
|
||||||
import org.geysermc.floodgate.api.logger.FloodgateLogger;
|
|
||||||
import org.geysermc.floodgate.config.FloodgateConfig;
|
import org.geysermc.floodgate.config.FloodgateConfig;
|
||||||
import org.geysermc.floodgate.config.FloodgateConfigHolder;
|
|
||||||
import org.geysermc.floodgate.pluginmessage.PluginMessageManager;
|
|
||||||
|
|
||||||
public final class ServerCommonModule extends CommonModule {
|
public final class ServerCommonModule extends CommonModule {
|
||||||
public ServerCommonModule(Path dataDirectory) {
|
public ServerCommonModule(Path dataDirectory) {
|
||||||
super(dataDirectory);
|
super(dataDirectory);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void configure() {
|
||||||
|
super.configure();
|
||||||
|
bind(SimpleFloodgateApi.class).in(Singleton.class);
|
||||||
|
}
|
||||||
|
|
||||||
@Provides
|
@Provides
|
||||||
@Singleton
|
@Singleton
|
||||||
@Named("configClass")
|
@Named("configClass")
|
||||||
public Class<? extends FloodgateConfig> floodgateConfigClass() {
|
public Class<? extends FloodgateConfig> floodgateConfigClass() {
|
||||||
return FloodgateConfig.class;
|
return FloodgateConfig.class;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Provides
|
|
||||||
@Singleton
|
|
||||||
public SimpleFloodgateApi floodgateApi(
|
|
||||||
PluginMessageManager pluginMessageManager,
|
|
||||||
FloodgateConfigHolder configHolder,
|
|
||||||
FloodgateLogger logger) {
|
|
||||||
return new SimpleFloodgateApi(pluginMessageManager, configHolder, logger);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -27,42 +27,50 @@ package org.geysermc.floodgate.news;
|
|||||||
|
|
||||||
import com.google.gson.JsonArray;
|
import com.google.gson.JsonArray;
|
||||||
import com.google.gson.JsonElement;
|
import com.google.gson.JsonElement;
|
||||||
|
import com.google.inject.Inject;
|
||||||
|
import com.google.inject.name.Named;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.concurrent.Executors;
|
|
||||||
import java.util.concurrent.ScheduledExecutorService;
|
import java.util.concurrent.ScheduledExecutorService;
|
||||||
import java.util.concurrent.TimeUnit;
|
import java.util.concurrent.TimeUnit;
|
||||||
import org.geysermc.floodgate.api.logger.FloodgateLogger;
|
import org.geysermc.floodgate.api.logger.FloodgateLogger;
|
||||||
|
import org.geysermc.floodgate.command.util.Permission;
|
||||||
import org.geysermc.floodgate.news.data.AnnouncementData;
|
import org.geysermc.floodgate.news.data.AnnouncementData;
|
||||||
import org.geysermc.floodgate.news.data.BuildSpecificData;
|
import org.geysermc.floodgate.news.data.BuildSpecificData;
|
||||||
import org.geysermc.floodgate.news.data.CheckAfterData;
|
import org.geysermc.floodgate.news.data.CheckAfterData;
|
||||||
import org.geysermc.floodgate.platform.command.CommandUtil;
|
import org.geysermc.floodgate.platform.command.CommandUtil;
|
||||||
|
import org.geysermc.floodgate.util.AutoBind;
|
||||||
import org.geysermc.floodgate.util.Constants;
|
import org.geysermc.floodgate.util.Constants;
|
||||||
import org.geysermc.floodgate.util.HttpUtils;
|
import org.geysermc.floodgate.util.HttpClient;
|
||||||
import org.geysermc.floodgate.util.HttpUtils.HttpResponse;
|
import org.geysermc.floodgate.util.HttpClient.HttpResponse;
|
||||||
import org.geysermc.floodgate.command.util.Permission;
|
|
||||||
|
|
||||||
|
@AutoBind
|
||||||
public class NewsChecker {
|
public class NewsChecker {
|
||||||
private final ScheduledExecutorService executorService = Executors.newScheduledThreadPool(1);
|
|
||||||
private final CommandUtil commandUtil;
|
|
||||||
private final FloodgateLogger logger;
|
|
||||||
|
|
||||||
private final Map<Integer, NewsItem> activeNewsItems = new HashMap<>();
|
private final Map<Integer, NewsItem> activeNewsItems = new HashMap<>();
|
||||||
private final String branch;
|
@Inject
|
||||||
private final int build;
|
@Named("commonScheduledPool")
|
||||||
|
private ScheduledExecutorService executorService;
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
private CommandUtil commandUtil;
|
||||||
|
@Inject
|
||||||
|
private HttpClient httpClient;
|
||||||
|
@Inject
|
||||||
|
private FloodgateLogger logger;
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
@Named("gitBranch")
|
||||||
|
private String branch;
|
||||||
|
@Inject
|
||||||
|
@Named("buildNumber")
|
||||||
|
private int build;
|
||||||
|
|
||||||
private boolean firstCheck;
|
private boolean firstCheck;
|
||||||
|
|
||||||
public NewsChecker(CommandUtil commandUtil, FloodgateLogger logger, String branch, int build) {
|
@Inject
|
||||||
this.commandUtil = commandUtil;
|
|
||||||
this.logger = logger;
|
|
||||||
this.branch = branch;
|
|
||||||
this.build = build;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void start() {
|
public void start() {
|
||||||
executorService.scheduleWithFixedDelay(this::checkNews, 0, 30, TimeUnit.MINUTES);
|
executorService.scheduleWithFixedDelay(this::checkNews, 0, 30, TimeUnit.MINUTES);
|
||||||
}
|
}
|
||||||
@@ -72,10 +80,10 @@ public class NewsChecker {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void checkNews() {
|
private void checkNews() {
|
||||||
HttpResponse<JsonArray> response =
|
HttpResponse<JsonArray> response = httpClient.getSilent(
|
||||||
HttpUtils.getSilent(
|
|
||||||
Constants.NEWS_OVERVIEW_URL + Constants.NEWS_PROJECT_NAME,
|
Constants.NEWS_OVERVIEW_URL + Constants.NEWS_PROJECT_NAME,
|
||||||
JsonArray.class);
|
JsonArray.class
|
||||||
|
);
|
||||||
|
|
||||||
JsonArray array = response.getResponse();
|
JsonArray array = response.getResponse();
|
||||||
|
|
||||||
@@ -193,8 +201,4 @@ public class NewsChecker {
|
|||||||
handleNewsItem(null, item, action);
|
handleNewsItem(null, item, action);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void shutdown() {
|
|
||||||
executorService.shutdown();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,40 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2019-2022 GeyserMC. http://geysermc.org
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
* of this software and associated documentation files (the "Software"), to deal
|
||||||
|
* in the Software without restriction, including without limitation the rights
|
||||||
|
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
* copies of the Software, and to permit persons to whom the Software is
|
||||||
|
* furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in
|
||||||
|
* all copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
|
* THE SOFTWARE.
|
||||||
|
*
|
||||||
|
* @author GeyserMC
|
||||||
|
* @link https://github.com/GeyserMC/Floodgate
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.geysermc.floodgate.platform.command;
|
||||||
|
|
||||||
|
import cloud.commandframework.context.CommandContext;
|
||||||
|
import org.geysermc.floodgate.command.util.Permission;
|
||||||
|
import org.geysermc.floodgate.player.UserAudience;
|
||||||
|
|
||||||
|
public abstract class FloodgateSubCommand {
|
||||||
|
public abstract String name();
|
||||||
|
|
||||||
|
public abstract String description();
|
||||||
|
|
||||||
|
public abstract Permission permission();
|
||||||
|
|
||||||
|
public abstract void execute(CommandContext<UserAudience> context);
|
||||||
|
}
|
||||||
@@ -23,33 +23,32 @@
|
|||||||
* @link https://github.com/GeyserMC/Floodgate
|
* @link https://github.com/GeyserMC/Floodgate
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package org.geysermc.floodgate;
|
package org.geysermc.floodgate.platform.command;
|
||||||
|
|
||||||
import com.google.inject.Inject;
|
import com.google.inject.Inject;
|
||||||
import com.google.inject.Injector;
|
import com.google.inject.Injector;
|
||||||
import com.google.inject.Module;
|
import java.util.Collections;
|
||||||
import org.bukkit.Bukkit;
|
import java.util.HashSet;
|
||||||
import org.bukkit.plugin.java.JavaPlugin;
|
import java.util.Set;
|
||||||
import org.geysermc.floodgate.api.FloodgateApi;
|
|
||||||
import org.geysermc.floodgate.api.inject.PlatformInjector;
|
|
||||||
import org.geysermc.floodgate.api.logger.FloodgateLogger;
|
|
||||||
|
|
||||||
public final class SpigotPlatform extends FloodgatePlatform {
|
public abstract class SubCommands {
|
||||||
@Inject private JavaPlugin plugin;
|
private final Set<Class<? extends FloodgateSubCommand>> toRegister = new HashSet<>();
|
||||||
|
private Set<FloodgateSubCommand> subCommands;
|
||||||
|
|
||||||
|
public void defineSubCommand(Class<? extends FloodgateSubCommand> subCommandClass) {
|
||||||
|
toRegister.add(subCommandClass);
|
||||||
|
}
|
||||||
|
|
||||||
@Inject
|
@Inject
|
||||||
public SpigotPlatform(FloodgateApi api, PlatformInjector platformInjector,
|
public void registerSubCommands(Injector injector) {
|
||||||
FloodgateLogger logger, Injector injector) {
|
Set<FloodgateSubCommand> subCommandSet = new HashSet<>();
|
||||||
super(api, platformInjector, logger, injector);
|
for (Class<? extends FloodgateSubCommand> subCommand : toRegister) {
|
||||||
|
subCommandSet.add(injector.getInstance(subCommand));
|
||||||
|
}
|
||||||
|
subCommands = Collections.unmodifiableSet(subCommandSet);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
protected Set<FloodgateSubCommand> subCommands() {
|
||||||
public boolean enable(Module... postInitializeModules) {
|
return subCommands;
|
||||||
boolean success = super.enable(postInitializeModules);
|
|
||||||
if (!success) {
|
|
||||||
Bukkit.getPluginManager().disablePlugin(plugin);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -48,11 +48,13 @@ import org.geysermc.floodgate.api.handshake.HandshakeData;
|
|||||||
import org.geysermc.floodgate.api.logger.FloodgateLogger;
|
import org.geysermc.floodgate.api.logger.FloodgateLogger;
|
||||||
import org.geysermc.floodgate.api.player.FloodgatePlayer;
|
import org.geysermc.floodgate.api.player.FloodgatePlayer;
|
||||||
import org.geysermc.floodgate.api.player.PropertyKey;
|
import org.geysermc.floodgate.api.player.PropertyKey;
|
||||||
import org.geysermc.floodgate.config.FloodgateConfigHolder;
|
import org.geysermc.floodgate.config.FloodgateConfig;
|
||||||
import org.geysermc.floodgate.crypto.FloodgateCipher;
|
import org.geysermc.floodgate.crypto.FloodgateCipher;
|
||||||
import org.geysermc.floodgate.skin.SkinUploadManager;
|
import org.geysermc.floodgate.skin.SkinUploadManager;
|
||||||
import org.geysermc.floodgate.util.BedrockData;
|
import org.geysermc.floodgate.util.BedrockData;
|
||||||
|
import org.geysermc.floodgate.util.Constants;
|
||||||
import org.geysermc.floodgate.util.InvalidFormatException;
|
import org.geysermc.floodgate.util.InvalidFormatException;
|
||||||
|
import org.geysermc.floodgate.util.LanguageManager;
|
||||||
import org.geysermc.floodgate.util.LinkedPlayer;
|
import org.geysermc.floodgate.util.LinkedPlayer;
|
||||||
import org.geysermc.floodgate.util.Utils;
|
import org.geysermc.floodgate.util.Utils;
|
||||||
|
|
||||||
@@ -60,27 +62,30 @@ public final class FloodgateHandshakeHandler {
|
|||||||
private final HandshakeHandlersImpl handshakeHandlers;
|
private final HandshakeHandlersImpl handshakeHandlers;
|
||||||
private final SimpleFloodgateApi api;
|
private final SimpleFloodgateApi api;
|
||||||
private final FloodgateCipher cipher;
|
private final FloodgateCipher cipher;
|
||||||
private final FloodgateConfigHolder configHolder;
|
private final FloodgateConfig config;
|
||||||
private final SkinUploadManager skinUploadManager;
|
private final SkinUploadManager skinUploadManager;
|
||||||
private final AttributeKey<FloodgatePlayer> playerAttribute;
|
private final AttributeKey<FloodgatePlayer> playerAttribute;
|
||||||
private final FloodgateLogger logger;
|
private final FloodgateLogger logger;
|
||||||
|
private final LanguageManager languageManager;
|
||||||
|
|
||||||
public FloodgateHandshakeHandler(
|
public FloodgateHandshakeHandler(
|
||||||
HandshakeHandlersImpl handshakeHandlers,
|
HandshakeHandlersImpl handshakeHandlers,
|
||||||
SimpleFloodgateApi api,
|
SimpleFloodgateApi api,
|
||||||
FloodgateCipher cipher,
|
FloodgateCipher cipher,
|
||||||
FloodgateConfigHolder configHolder,
|
FloodgateConfig config,
|
||||||
SkinUploadManager skinUploadManager,
|
SkinUploadManager skinUploadManager,
|
||||||
AttributeKey<FloodgatePlayer> playerAttribute,
|
AttributeKey<FloodgatePlayer> playerAttribute,
|
||||||
FloodgateLogger logger) {
|
FloodgateLogger logger,
|
||||||
|
LanguageManager languageManager) {
|
||||||
|
|
||||||
this.handshakeHandlers = handshakeHandlers;
|
this.handshakeHandlers = handshakeHandlers;
|
||||||
this.api = api;
|
this.api = api;
|
||||||
this.cipher = cipher;
|
this.cipher = cipher;
|
||||||
this.configHolder = configHolder;
|
this.config = config;
|
||||||
this.skinUploadManager = skinUploadManager;
|
this.skinUploadManager = skinUploadManager;
|
||||||
this.playerAttribute = playerAttribute;
|
this.playerAttribute = playerAttribute;
|
||||||
this.logger = logger;
|
this.logger = logger;
|
||||||
|
this.languageManager = languageManager;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -134,7 +139,7 @@ public final class FloodgateHandshakeHandler {
|
|||||||
);
|
);
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
// all the other exceptions are caused by invalid/tempered Floodgate data
|
// all the other exceptions are caused by invalid/tempered Floodgate data
|
||||||
if (configHolder.get().isDebug()) {
|
if (config.isDebug()) {
|
||||||
e.printStackTrace();
|
e.printStackTrace();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -207,11 +212,16 @@ public final class FloodgateHandshakeHandler {
|
|||||||
|
|
||||||
try {
|
try {
|
||||||
HandshakeData handshakeData = new HandshakeDataImpl(
|
HandshakeData handshakeData = new HandshakeDataImpl(
|
||||||
channel, true, bedrockData.clone(), configHolder.get(),
|
channel, true, bedrockData.clone(), config,
|
||||||
linkedPlayer != null ? linkedPlayer.clone() : null, hostname);
|
linkedPlayer != null ? linkedPlayer.clone() : null, hostname);
|
||||||
|
|
||||||
if (configHolder.get().getPlayerLink().isRequireLink() && linkedPlayer == null) {
|
if (config.getPlayerLink().isRequireLink() && linkedPlayer == null) {
|
||||||
handshakeData.setDisconnectReason("floodgate.core.not_linked");
|
String reason = languageManager.getString(
|
||||||
|
"floodgate.core.not_linked",
|
||||||
|
bedrockData.getLanguageCode(),
|
||||||
|
Constants.LINK_INFO_URL
|
||||||
|
);
|
||||||
|
handshakeData.setDisconnectReason(reason);
|
||||||
}
|
}
|
||||||
|
|
||||||
handshakeHandlers.callHandshakeHandlers(handshakeData);
|
handshakeHandlers.callHandshakeHandlers(handshakeData);
|
||||||
@@ -245,7 +255,7 @@ public final class FloodgateHandshakeHandler {
|
|||||||
String hostname) {
|
String hostname) {
|
||||||
|
|
||||||
HandshakeData handshakeData = new HandshakeDataImpl(channel, bedrockData != null,
|
HandshakeData handshakeData = new HandshakeDataImpl(channel, bedrockData != null,
|
||||||
bedrockData, configHolder.get(), null, hostname);
|
bedrockData, config, null, hostname);
|
||||||
handshakeHandlers.callHandshakeHandlers(handshakeData);
|
handshakeHandlers.callHandshakeHandlers(handshakeData);
|
||||||
|
|
||||||
return new HandshakeResult(resultType, handshakeData, bedrockData, null);
|
return new HandshakeResult(resultType, handshakeData, bedrockData, null);
|
||||||
|
|||||||
@@ -32,7 +32,6 @@ import lombok.AccessLevel;
|
|||||||
import lombok.Getter;
|
import lombok.Getter;
|
||||||
import lombok.RequiredArgsConstructor;
|
import lombok.RequiredArgsConstructor;
|
||||||
import org.geysermc.floodgate.api.FloodgateApi;
|
import org.geysermc.floodgate.api.FloodgateApi;
|
||||||
import org.geysermc.floodgate.api.InstanceHolder;
|
|
||||||
import org.geysermc.floodgate.api.ProxyFloodgateApi;
|
import org.geysermc.floodgate.api.ProxyFloodgateApi;
|
||||||
import org.geysermc.floodgate.api.handshake.HandshakeData;
|
import org.geysermc.floodgate.api.handshake.HandshakeData;
|
||||||
import org.geysermc.floodgate.api.player.FloodgatePlayer;
|
import org.geysermc.floodgate.api.player.FloodgatePlayer;
|
||||||
@@ -72,7 +71,7 @@ public final class FloodgatePlayerImpl implements FloodgatePlayer {
|
|||||||
private Map<String, PropertyKey> stringToPropertyKey;
|
private Map<String, PropertyKey> stringToPropertyKey;
|
||||||
|
|
||||||
static FloodgatePlayerImpl from(BedrockData data, HandshakeData handshakeData) {
|
static FloodgatePlayerImpl from(BedrockData data, HandshakeData handshakeData) {
|
||||||
FloodgateApi api = InstanceHolder.getApi();
|
FloodgateApi api = FloodgateApi.getInstance();
|
||||||
|
|
||||||
UUID javaUniqueId = Utils.getJavaUuid(data.getXuid());
|
UUID javaUniqueId = Utils.getJavaUuid(data.getXuid());
|
||||||
|
|
||||||
|
|||||||
@@ -36,14 +36,12 @@ public interface PluginMessageChannel {
|
|||||||
|
|
||||||
Result handleProxyCall(
|
Result handleProxyCall(
|
||||||
byte[] data,
|
byte[] data,
|
||||||
UUID targetUuid,
|
|
||||||
String targetUsername,
|
|
||||||
Identity targetIdentity,
|
|
||||||
UUID sourceUuid,
|
UUID sourceUuid,
|
||||||
String sourceUsername,
|
String sourceUsername,
|
||||||
Identity sourceIdentity);
|
Identity sourceIdentity
|
||||||
|
);
|
||||||
|
|
||||||
Result handleServerCall(byte[] data, UUID targetUuid, String targetUsername);
|
Result handleServerCall(byte[] data, UUID playerUuid, String playerUsername);
|
||||||
|
|
||||||
@Getter
|
@Getter
|
||||||
@RequiredArgsConstructor(access = AccessLevel.PRIVATE)
|
@RequiredArgsConstructor(access = AccessLevel.PRIVATE)
|
||||||
|
|||||||
@@ -28,6 +28,7 @@ package org.geysermc.floodgate.pluginmessage.channel;
|
|||||||
import com.google.common.base.Charsets;
|
import com.google.common.base.Charsets;
|
||||||
import com.google.inject.Inject;
|
import com.google.inject.Inject;
|
||||||
import it.unimi.dsi.fastutil.shorts.Short2ObjectMap;
|
import it.unimi.dsi.fastutil.shorts.Short2ObjectMap;
|
||||||
|
import it.unimi.dsi.fastutil.shorts.Short2ObjectMaps;
|
||||||
import it.unimi.dsi.fastutil.shorts.Short2ObjectOpenHashMap;
|
import it.unimi.dsi.fastutil.shorts.Short2ObjectOpenHashMap;
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
import java.util.concurrent.atomic.AtomicInteger;
|
import java.util.concurrent.atomic.AtomicInteger;
|
||||||
@@ -41,7 +42,8 @@ import org.geysermc.floodgate.pluginmessage.PluginMessageChannel;
|
|||||||
|
|
||||||
public class FormChannel implements PluginMessageChannel {
|
public class FormChannel implements PluginMessageChannel {
|
||||||
private final FormDefinitions formDefinitions = FormDefinitions.instance();
|
private final FormDefinitions formDefinitions = FormDefinitions.instance();
|
||||||
private final Short2ObjectMap<Form> storedForms = new Short2ObjectOpenHashMap<>();
|
private final Short2ObjectMap<Form> storedForms =
|
||||||
|
Short2ObjectMaps.synchronize(new Short2ObjectOpenHashMap<>());
|
||||||
private final AtomicInteger nextFormId = new AtomicInteger(0);
|
private final AtomicInteger nextFormId = new AtomicInteger(0);
|
||||||
|
|
||||||
@Inject private PluginMessageUtils pluginMessageUtils;
|
@Inject private PluginMessageUtils pluginMessageUtils;
|
||||||
@@ -56,13 +58,10 @@ public class FormChannel implements PluginMessageChannel {
|
|||||||
@Override
|
@Override
|
||||||
public Result handleProxyCall(
|
public Result handleProxyCall(
|
||||||
byte[] data,
|
byte[] data,
|
||||||
UUID targetUuid,
|
|
||||||
String targetUsername,
|
|
||||||
Identity targetIdentity,
|
|
||||||
UUID sourceUuid,
|
UUID sourceUuid,
|
||||||
String sourceUsername,
|
String sourceUsername,
|
||||||
Identity sourceIdentity) {
|
Identity sourceIdentity
|
||||||
|
) {
|
||||||
if (sourceIdentity == Identity.SERVER) {
|
if (sourceIdentity == Identity.SERVER) {
|
||||||
// send it to the client
|
// send it to the client
|
||||||
return Result.forward();
|
return Result.forward();
|
||||||
@@ -89,7 +88,7 @@ public class FormChannel implements PluginMessageChannel {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Result handleServerCall(byte[] data, UUID targetUuid, String targetUsername) {
|
public Result handleServerCall(byte[] data, UUID playerUuid, String playerUsername) {
|
||||||
callResponseConsumer(data);
|
callResponseConsumer(data);
|
||||||
return Result.handled();
|
return Result.handled();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -40,23 +40,26 @@ public final class PacketChannel implements PluginMessageChannel {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Result handleProxyCall(byte[] data, UUID targetUuid, String targetUsername,
|
public Result handleProxyCall(
|
||||||
Identity targetIdentity, UUID sourceUuid, String sourceUsername,
|
byte[] data,
|
||||||
Identity sourceIdentity) {
|
UUID sourceUuid,
|
||||||
|
String sourceUsername,
|
||||||
|
Identity sourceIdentity
|
||||||
|
) {
|
||||||
if (sourceIdentity == Identity.SERVER) {
|
if (sourceIdentity == Identity.SERVER) {
|
||||||
// send it to the client
|
// send it to the client
|
||||||
return Result.forward();
|
return Result.forward();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (sourceIdentity == Identity.PLAYER) {
|
if (sourceIdentity == Identity.PLAYER) {
|
||||||
return handleServerCall(data, targetUuid, targetUsername);
|
return handleServerCall(data, sourceUuid, sourceUsername);
|
||||||
}
|
}
|
||||||
|
|
||||||
return Result.handled();
|
return Result.handled();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Result handleServerCall(byte[] data, UUID targetUuid, String targetUsername) {
|
public Result handleServerCall(byte[] data, UUID playerUuid, String playerUsername) {
|
||||||
return Result.kick("Cannot send packets from Geyser/Floodgate to Floodgate");
|
return Result.kick("Cannot send packets from Geyser/Floodgate to Floodgate");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -25,7 +25,6 @@
|
|||||||
|
|
||||||
package org.geysermc.floodgate.pluginmessage.channel;
|
package org.geysermc.floodgate.pluginmessage.channel;
|
||||||
|
|
||||||
import com.google.gson.JsonObject;
|
|
||||||
import com.google.inject.Inject;
|
import com.google.inject.Inject;
|
||||||
import java.nio.charset.StandardCharsets;
|
import java.nio.charset.StandardCharsets;
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
@@ -36,7 +35,7 @@ import org.geysermc.floodgate.config.FloodgateConfig;
|
|||||||
import org.geysermc.floodgate.config.ProxyFloodgateConfig;
|
import org.geysermc.floodgate.config.ProxyFloodgateConfig;
|
||||||
import org.geysermc.floodgate.pluginmessage.PluginMessageChannel;
|
import org.geysermc.floodgate.pluginmessage.PluginMessageChannel;
|
||||||
import org.geysermc.floodgate.skin.SkinApplier;
|
import org.geysermc.floodgate.skin.SkinApplier;
|
||||||
import org.geysermc.floodgate.skin.SkinData;
|
import org.geysermc.floodgate.skin.SkinDataImpl;
|
||||||
|
|
||||||
public class SkinChannel implements PluginMessageChannel {
|
public class SkinChannel implements PluginMessageChannel {
|
||||||
@Inject private FloodgateApi api;
|
@Inject private FloodgateApi api;
|
||||||
@@ -51,16 +50,13 @@ public class SkinChannel implements PluginMessageChannel {
|
|||||||
@Override
|
@Override
|
||||||
public Result handleProxyCall(
|
public Result handleProxyCall(
|
||||||
byte[] data,
|
byte[] data,
|
||||||
UUID targetUuid,
|
|
||||||
String targetUsername,
|
|
||||||
Identity targetIdentity,
|
|
||||||
UUID sourceUuid,
|
UUID sourceUuid,
|
||||||
String sourceUsername,
|
String sourceUsername,
|
||||||
Identity sourceIdentity) {
|
Identity sourceIdentity
|
||||||
|
) {
|
||||||
// we can only get skins from Geyser (client)
|
// we can only get skins from Geyser (client)
|
||||||
if (sourceIdentity == Identity.PLAYER) {
|
if (sourceIdentity == Identity.PLAYER) {
|
||||||
Result result = handleServerCall(data, targetUuid, targetUsername);
|
Result result = handleServerCall(data, sourceUuid, sourceUsername);
|
||||||
// aka translate 'handled' into 'forward' when send-floodgate-data is enabled
|
// aka translate 'handled' into 'forward' when send-floodgate-data is enabled
|
||||||
if (!result.isAllowed() && result.getReason() == null) {
|
if (!result.isAllowed() && result.getReason() == null) {
|
||||||
if (config.isProxy() && ((ProxyFloodgateConfig) config).isSendFloodgateData()) {
|
if (config.isProxy() && ((ProxyFloodgateConfig) config).isSendFloodgateData()) {
|
||||||
@@ -78,8 +74,8 @@ public class SkinChannel implements PluginMessageChannel {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Result handleServerCall(byte[] data, UUID targetUuid, String targetUsername) {
|
public Result handleServerCall(byte[] data, UUID playerUuid, String playerUsername) {
|
||||||
FloodgatePlayer floodgatePlayer = api.getPlayer(targetUuid);
|
FloodgatePlayer floodgatePlayer = api.getPlayer(playerUuid);
|
||||||
if (floodgatePlayer == null) {
|
if (floodgatePlayer == null) {
|
||||||
return Result.kick("Player sent skins data for a non-Floodgate player");
|
return Result.kick("Player sent skins data for a non-Floodgate player");
|
||||||
}
|
}
|
||||||
@@ -92,18 +88,10 @@ public class SkinChannel implements PluginMessageChannel {
|
|||||||
return Result.kick("Got invalid skin data");
|
return Result.kick("Got invalid skin data");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (floodgatePlayer.isLinked()) {
|
|
||||||
return Result.handled();
|
|
||||||
}
|
|
||||||
|
|
||||||
String value = split[0];
|
String value = split[0];
|
||||||
String signature = split[1];
|
String signature = split[1];
|
||||||
|
|
||||||
JsonObject result = new JsonObject();
|
SkinDataImpl skinData = new SkinDataImpl(value, signature);
|
||||||
result.addProperty("value", value);
|
|
||||||
result.addProperty("signature", signature);
|
|
||||||
|
|
||||||
SkinData skinData = new SkinData(value, signature);
|
|
||||||
|
|
||||||
floodgatePlayer.addProperty(PropertyKey.SKIN_UPLOADED, skinData);
|
floodgatePlayer.addProperty(PropertyKey.SKIN_UPLOADED, skinData);
|
||||||
skinApplier.applySkin(floodgatePlayer, skinData);
|
skinApplier.applySkin(floodgatePlayer, skinData);
|
||||||
|
|||||||
@@ -42,27 +42,24 @@ public class TransferChannel implements PluginMessageChannel {
|
|||||||
@Override
|
@Override
|
||||||
public Result handleProxyCall(
|
public Result handleProxyCall(
|
||||||
byte[] data,
|
byte[] data,
|
||||||
UUID targetUuid,
|
|
||||||
String targetUsername,
|
|
||||||
Identity targetIdentity,
|
|
||||||
UUID sourceUuid,
|
UUID sourceUuid,
|
||||||
String sourceUsername,
|
String sourceUsername,
|
||||||
Identity sourceIdentity) {
|
Identity sourceIdentity
|
||||||
|
) {
|
||||||
if (sourceIdentity == Identity.SERVER) {
|
if (sourceIdentity == Identity.SERVER) {
|
||||||
// send it to the client
|
// send it to the client
|
||||||
return Result.forward();
|
return Result.forward();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (sourceIdentity == Identity.PLAYER) {
|
if (sourceIdentity == Identity.PLAYER) {
|
||||||
handleServerCall(data, targetUuid, targetUsername);
|
handleServerCall(data, sourceUuid, sourceUsername);
|
||||||
}
|
}
|
||||||
|
|
||||||
return Result.handled();
|
return Result.handled();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Result handleServerCall(byte[] data, UUID targetUuid, String targetUsername) {
|
public Result handleServerCall(byte[] data, UUID playerUuid, String playerUsername) {
|
||||||
return Result.kick("I'm sorry, I'm unable to transfer a server :(");
|
return Result.kick("I'm sorry, I'm unable to transfer a server :(");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -25,8 +25,16 @@
|
|||||||
|
|
||||||
package org.geysermc.floodgate.skin;
|
package org.geysermc.floodgate.skin;
|
||||||
|
|
||||||
|
import org.checkerframework.checker.nullness.qual.NonNull;
|
||||||
|
import org.geysermc.floodgate.api.event.skin.SkinApplyEvent.SkinData;
|
||||||
import org.geysermc.floodgate.api.player.FloodgatePlayer;
|
import org.geysermc.floodgate.api.player.FloodgatePlayer;
|
||||||
|
|
||||||
public interface SkinApplier {
|
public interface SkinApplier {
|
||||||
void applySkin(FloodgatePlayer floodgatePlayer, SkinData skinData);
|
/**
|
||||||
|
* Apply a skin to a {@link FloodgatePlayer player}
|
||||||
|
*
|
||||||
|
* @param floodgatePlayer player to apply skin to
|
||||||
|
* @param skinData data for skin to apply to player
|
||||||
|
*/
|
||||||
|
void applySkin(@NonNull FloodgatePlayer floodgatePlayer, @NonNull SkinData skinData);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,58 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2019-2022 GeyserMC. http://geysermc.org
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
* of this software and associated documentation files (the "Software"), to deal
|
||||||
|
* in the Software without restriction, including without limitation the rights
|
||||||
|
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
* copies of the Software, and to permit persons to whom the Software is
|
||||||
|
* furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in
|
||||||
|
* all copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
|
* THE SOFTWARE.
|
||||||
|
*
|
||||||
|
* @author GeyserMC
|
||||||
|
* @link https://github.com/GeyserMC/Floodgate
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.geysermc.floodgate.skin;
|
||||||
|
|
||||||
|
import com.google.gson.JsonObject;
|
||||||
|
import java.util.Objects;
|
||||||
|
import org.checkerframework.checker.nullness.qual.NonNull;
|
||||||
|
import org.geysermc.floodgate.api.event.skin.SkinApplyEvent.SkinData;
|
||||||
|
|
||||||
|
public class SkinDataImpl implements SkinData {
|
||||||
|
private final String value;
|
||||||
|
private final String signature;
|
||||||
|
|
||||||
|
public SkinDataImpl(@NonNull String value, @NonNull String signature) {
|
||||||
|
this.value = Objects.requireNonNull(value);
|
||||||
|
this.signature = Objects.requireNonNull(signature);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static SkinData from(JsonObject data) {
|
||||||
|
return new SkinDataImpl(
|
||||||
|
data.get("value").getAsString(),
|
||||||
|
data.get("signature").getAsString()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public @NonNull String value() {
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public @NonNull String signature() {
|
||||||
|
return signature;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -25,21 +25,26 @@
|
|||||||
|
|
||||||
package org.geysermc.floodgate.skin;
|
package org.geysermc.floodgate.skin;
|
||||||
|
|
||||||
|
import com.google.inject.Inject;
|
||||||
|
import com.google.inject.Singleton;
|
||||||
import it.unimi.dsi.fastutil.ints.Int2ObjectMap;
|
import it.unimi.dsi.fastutil.ints.Int2ObjectMap;
|
||||||
import it.unimi.dsi.fastutil.ints.Int2ObjectMaps;
|
import it.unimi.dsi.fastutil.ints.Int2ObjectMaps;
|
||||||
import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap;
|
import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap;
|
||||||
import lombok.AllArgsConstructor;
|
import org.geysermc.event.Listener;
|
||||||
|
import org.geysermc.event.subscribe.Subscribe;
|
||||||
import org.geysermc.floodgate.api.FloodgateApi;
|
import org.geysermc.floodgate.api.FloodgateApi;
|
||||||
import org.geysermc.floodgate.api.logger.FloodgateLogger;
|
import org.geysermc.floodgate.api.logger.FloodgateLogger;
|
||||||
|
import org.geysermc.floodgate.event.lifecycle.ShutdownEvent;
|
||||||
|
|
||||||
@AllArgsConstructor
|
@Listener
|
||||||
|
@Singleton
|
||||||
public final class SkinUploadManager {
|
public final class SkinUploadManager {
|
||||||
private final Int2ObjectMap<SkinUploadSocket> connections =
|
private final Int2ObjectMap<SkinUploadSocket> connections =
|
||||||
Int2ObjectMaps.synchronize(new Int2ObjectOpenHashMap<>());
|
Int2ObjectMaps.synchronize(new Int2ObjectOpenHashMap<>());
|
||||||
|
|
||||||
private final FloodgateApi api;
|
@Inject private FloodgateApi api;
|
||||||
private final SkinApplier applier;
|
@Inject private SkinApplier applier;
|
||||||
private final FloodgateLogger logger;
|
@Inject private FloodgateLogger logger;
|
||||||
|
|
||||||
public void addConnectionIfNeeded(int id, String verifyCode) {
|
public void addConnectionIfNeeded(int id, String verifyCode) {
|
||||||
connections.computeIfAbsent(id, (ignored) -> {
|
connections.computeIfAbsent(id, (ignored) -> {
|
||||||
@@ -53,4 +58,16 @@ public final class SkinUploadManager {
|
|||||||
public void removeConnection(int id, SkinUploadSocket socket) {
|
public void removeConnection(int id, SkinUploadSocket socket) {
|
||||||
connections.remove(id, socket);
|
connections.remove(id, socket);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void closeAllSockets() {
|
||||||
|
for (SkinUploadSocket socket : connections.values()) {
|
||||||
|
socket.close();
|
||||||
|
}
|
||||||
|
connections.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Subscribe
|
||||||
|
public void onShutdown(ShutdownEvent ignored) {
|
||||||
|
closeAllSockets();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -35,6 +35,7 @@ import java.net.URI;
|
|||||||
import javax.net.ssl.SSLException;
|
import javax.net.ssl.SSLException;
|
||||||
import lombok.Getter;
|
import lombok.Getter;
|
||||||
import org.geysermc.floodgate.api.FloodgateApi;
|
import org.geysermc.floodgate.api.FloodgateApi;
|
||||||
|
import org.geysermc.floodgate.api.event.skin.SkinApplyEvent.SkinData;
|
||||||
import org.geysermc.floodgate.api.logger.FloodgateLogger;
|
import org.geysermc.floodgate.api.logger.FloodgateLogger;
|
||||||
import org.geysermc.floodgate.api.player.FloodgatePlayer;
|
import org.geysermc.floodgate.api.player.FloodgatePlayer;
|
||||||
import org.geysermc.floodgate.api.player.PropertyKey;
|
import org.geysermc.floodgate.api.player.PropertyKey;
|
||||||
@@ -61,8 +62,8 @@ final class SkinUploadSocket extends WebSocketClient {
|
|||||||
SkinUploadManager uploadManager,
|
SkinUploadManager uploadManager,
|
||||||
FloodgateApi api,
|
FloodgateApi api,
|
||||||
SkinApplier applier,
|
SkinApplier applier,
|
||||||
FloodgateLogger logger) {
|
FloodgateLogger logger
|
||||||
|
) {
|
||||||
super(getWebsocketUri(id, verifyCode));
|
super(getWebsocketUri(id, verifyCode));
|
||||||
this.id = id;
|
this.id = id;
|
||||||
this.verifyCode = verifyCode;
|
this.verifyCode = verifyCode;
|
||||||
@@ -83,7 +84,7 @@ final class SkinUploadSocket extends WebSocketClient {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onOpen(ServerHandshake handshakedata) {
|
public void onOpen(ServerHandshake ignored) {
|
||||||
setConnectionLostTimeout(11);
|
setConnectionLostTimeout(11);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -114,10 +115,14 @@ final class SkinUploadSocket extends WebSocketClient {
|
|||||||
player.getCorrectUsername());
|
player.getCorrectUsername());
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (!player.isLinked()) {
|
|
||||||
SkinData skinData = SkinData.from(message.getAsJsonObject("data"));
|
SkinData skinData = SkinDataImpl.from(message.getAsJsonObject("data"));
|
||||||
player.addProperty(PropertyKey.SKIN_UPLOADED, skinData);
|
|
||||||
applier.applySkin(player, skinData);
|
applier.applySkin(player, skinData);
|
||||||
|
|
||||||
|
// legacy stuff,
|
||||||
|
// will be removed shortly after or during the Floodgate-Geyser integration
|
||||||
|
if (!player.isLinked()) {
|
||||||
|
player.addProperty(PropertyKey.SKIN_UPLOADED, skinData);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|||||||
38
core/src/main/java/org/geysermc/floodgate/util/AutoBind.java
Normal file
38
core/src/main/java/org/geysermc/floodgate/util/AutoBind.java
Normal file
@@ -0,0 +1,38 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2019-2022 GeyserMC. http://geysermc.org
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
* of this software and associated documentation files (the "Software"), to deal
|
||||||
|
* in the Software without restriction, including without limitation the rights
|
||||||
|
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
* copies of the Software, and to permit persons to whom the Software is
|
||||||
|
* furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in
|
||||||
|
* all copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
|
* THE SOFTWARE.
|
||||||
|
*
|
||||||
|
* @author GeyserMC
|
||||||
|
* @link https://github.com/GeyserMC/Floodgate
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.geysermc.floodgate.util;
|
||||||
|
|
||||||
|
import java.lang.annotation.Retention;
|
||||||
|
import java.lang.annotation.RetentionPolicy;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Automatically binds an instance of itself as an eager singleton during the post-initialise stage
|
||||||
|
* of the FloodgatePlatform. Add the annotation to a class, and it should automatically create an
|
||||||
|
* instance and inject it for you.
|
||||||
|
*/
|
||||||
|
@Retention(RetentionPolicy.RUNTIME)
|
||||||
|
public @interface AutoBind {
|
||||||
|
}
|
||||||
@@ -27,13 +27,15 @@ package org.geysermc.floodgate.util;
|
|||||||
|
|
||||||
import com.google.gson.Gson;
|
import com.google.gson.Gson;
|
||||||
import com.google.gson.JsonObject;
|
import com.google.gson.JsonObject;
|
||||||
|
import com.google.inject.Inject;
|
||||||
|
import com.google.inject.Singleton;
|
||||||
|
import com.google.inject.name.Named;
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
import java.io.InputStreamReader;
|
import java.io.InputStreamReader;
|
||||||
import java.net.HttpURLConnection;
|
import java.net.HttpURLConnection;
|
||||||
import java.net.URL;
|
import java.net.URL;
|
||||||
import java.util.concurrent.CompletableFuture;
|
import java.util.concurrent.CompletableFuture;
|
||||||
import java.util.concurrent.ExecutorService;
|
import java.util.concurrent.ExecutorService;
|
||||||
import java.util.concurrent.Executors;
|
|
||||||
import lombok.AccessLevel;
|
import lombok.AccessLevel;
|
||||||
import lombok.AllArgsConstructor;
|
import lombok.AllArgsConstructor;
|
||||||
import lombok.Getter;
|
import lombok.Getter;
|
||||||
@@ -42,29 +44,36 @@ import org.checkerframework.checker.nullness.qual.Nullable;
|
|||||||
|
|
||||||
// resources are properly closed and ignoring the original stack trace is intended
|
// resources are properly closed and ignoring the original stack trace is intended
|
||||||
@SuppressWarnings({"PMD.CloseResource", "PMD.PreserveStackTrace"})
|
@SuppressWarnings({"PMD.CloseResource", "PMD.PreserveStackTrace"})
|
||||||
public class HttpUtils {
|
@Singleton
|
||||||
private static final ExecutorService EXECUTOR_SERVICE = Executors.newSingleThreadExecutor();
|
public class HttpClient {
|
||||||
|
|
||||||
private static final Gson GSON = new Gson();
|
|
||||||
private static final String USER_AGENT = "GeyserMC/Floodgate";
|
private static final String USER_AGENT = "GeyserMC/Floodgate";
|
||||||
|
|
||||||
public static CompletableFuture<DefaultHttpResponse> asyncGet(String urlString) {
|
private final Gson gson = new Gson();
|
||||||
return CompletableFuture.supplyAsync(() -> get(urlString), EXECUTOR_SERVICE);
|
@Inject
|
||||||
|
@Named("commonPool")
|
||||||
|
private ExecutorService executorService;
|
||||||
|
|
||||||
|
public CompletableFuture<DefaultHttpResponse> asyncGet(String urlString) {
|
||||||
|
return CompletableFuture.supplyAsync(() -> get(urlString), executorService);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static DefaultHttpResponse get(String urlString) {
|
public <T> CompletableFuture<HttpResponse<T>> asyncGet(String urlString, Class<T> response) {
|
||||||
|
return CompletableFuture.supplyAsync(() -> get(urlString, response), executorService);
|
||||||
|
}
|
||||||
|
|
||||||
|
public DefaultHttpResponse get(String urlString) {
|
||||||
return readDefaultResponse(request(urlString));
|
return readDefaultResponse(request(urlString));
|
||||||
}
|
}
|
||||||
|
|
||||||
public static <T> HttpResponse<T> get(String urlString, Class<T> clazz) {
|
public <T> HttpResponse<T> get(String urlString, Class<T> clazz) {
|
||||||
return readResponse(request(urlString), clazz);
|
return readResponse(request(urlString), clazz);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static <T> HttpResponse<T> getSilent(String urlString, Class<T> clazz) {
|
public <T> HttpResponse<T> getSilent(String urlString, Class<T> clazz) {
|
||||||
return readResponseSilent(request(urlString), clazz);
|
return readResponseSilent(request(urlString), clazz);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static HttpURLConnection request(String urlString) {
|
private HttpURLConnection request(String urlString) {
|
||||||
HttpURLConnection connection;
|
HttpURLConnection connection;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
@@ -88,18 +97,20 @@ public class HttpUtils {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@NonNull
|
@NonNull
|
||||||
private static <T> HttpResponse<T> readResponse(HttpURLConnection connection, Class<T> clazz) {
|
private <T> HttpResponse<T> readResponse(HttpURLConnection connection, Class<T> clazz) {
|
||||||
InputStreamReader streamReader = createReader(connection);
|
InputStreamReader streamReader = createReader(connection);
|
||||||
if (streamReader == null) {
|
if (streamReader == null) {
|
||||||
return new HttpResponse<>(-1, null);
|
return new HttpResponse<>(-1, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int responseCode = -1;
|
||||||
try {
|
try {
|
||||||
int responseCode = connection.getResponseCode();
|
responseCode = connection.getResponseCode();
|
||||||
T response = GSON.fromJson(streamReader, clazz);
|
T response = gson.fromJson(streamReader, clazz);
|
||||||
return new HttpResponse<>(responseCode, response);
|
return new HttpResponse<>(responseCode, response);
|
||||||
} catch (Exception ignored) {
|
} catch (Exception ignored) {
|
||||||
return new HttpResponse<>(-1, null);
|
// e.g. when the response isn't JSON
|
||||||
|
return new HttpResponse<>(responseCode, null);
|
||||||
} finally {
|
} finally {
|
||||||
try {
|
try {
|
||||||
streamReader.close();
|
streamReader.close();
|
||||||
@@ -109,9 +120,7 @@ public class HttpUtils {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@NonNull
|
@NonNull
|
||||||
private static <T> HttpResponse<T> readResponseSilent(
|
private <T> HttpResponse<T> readResponseSilent(HttpURLConnection connection, Class<T> clazz) {
|
||||||
HttpURLConnection connection,
|
|
||||||
Class<T> clazz) {
|
|
||||||
try {
|
try {
|
||||||
return readResponse(connection, clazz);
|
return readResponse(connection, clazz);
|
||||||
} catch (Exception ignored) {
|
} catch (Exception ignored) {
|
||||||
@@ -120,7 +129,7 @@ public class HttpUtils {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@NonNull
|
@NonNull
|
||||||
private static DefaultHttpResponse readDefaultResponse(HttpURLConnection connection) {
|
private DefaultHttpResponse readDefaultResponse(HttpURLConnection connection) {
|
||||||
InputStreamReader streamReader = createReader(connection);
|
InputStreamReader streamReader = createReader(connection);
|
||||||
if (streamReader == null) {
|
if (streamReader == null) {
|
||||||
return new DefaultHttpResponse(-1, null);
|
return new DefaultHttpResponse(-1, null);
|
||||||
@@ -128,7 +137,7 @@ public class HttpUtils {
|
|||||||
|
|
||||||
try {
|
try {
|
||||||
int responseCode = connection.getResponseCode();
|
int responseCode = connection.getResponseCode();
|
||||||
JsonObject response = GSON.fromJson(streamReader, JsonObject.class);
|
JsonObject response = gson.fromJson(streamReader, JsonObject.class);
|
||||||
return new DefaultHttpResponse(responseCode, response);
|
return new DefaultHttpResponse(responseCode, response);
|
||||||
} catch (Exception exception) {
|
} catch (Exception exception) {
|
||||||
throw new RuntimeException("Failed to read response", exception);
|
throw new RuntimeException("Failed to read response", exception);
|
||||||
@@ -141,16 +150,12 @@ public class HttpUtils {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Nullable
|
@Nullable
|
||||||
private static InputStreamReader createReader(HttpURLConnection connection) {
|
private InputStreamReader createReader(HttpURLConnection connection) {
|
||||||
InputStream stream;
|
InputStream stream;
|
||||||
try {
|
try {
|
||||||
stream = connection.getInputStream();
|
stream = connection.getInputStream();
|
||||||
} catch (Exception exception) {
|
} catch (Exception exception) {
|
||||||
try {
|
|
||||||
stream = connection.getErrorStream();
|
stream = connection.getErrorStream();
|
||||||
} catch (Exception exception1) {
|
|
||||||
throw new RuntimeException("Both the input and the error stream failed?!");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// it's null for example when it couldn't connect to the server
|
// it's null for example when it couldn't connect to the server
|
||||||
@@ -26,30 +26,27 @@
|
|||||||
package org.geysermc.floodgate.util;
|
package org.geysermc.floodgate.util;
|
||||||
|
|
||||||
import com.google.common.base.Joiner;
|
import com.google.common.base.Joiner;
|
||||||
import java.io.InputStream;
|
import com.google.inject.Inject;
|
||||||
import java.io.InputStreamReader;
|
import com.google.inject.Singleton;
|
||||||
import java.io.Reader;
|
|
||||||
import java.net.URL;
|
import java.net.URL;
|
||||||
import java.nio.charset.StandardCharsets;
|
|
||||||
import java.text.MessageFormat;
|
import java.text.MessageFormat;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.Locale;
|
import java.util.Locale;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Properties;
|
import java.util.Properties;
|
||||||
import lombok.Getter;
|
import lombok.Getter;
|
||||||
import lombok.RequiredArgsConstructor;
|
|
||||||
import org.geysermc.floodgate.api.logger.FloodgateLogger;
|
import org.geysermc.floodgate.api.logger.FloodgateLogger;
|
||||||
import org.geysermc.floodgate.config.FloodgateConfig;
|
import org.geysermc.floodgate.config.FloodgateConfig;
|
||||||
import org.geysermc.floodgate.config.FloodgateConfigHolder;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Manages translations for strings in Floodgate
|
* Manages translations for strings in Floodgate
|
||||||
*/
|
*/
|
||||||
@RequiredArgsConstructor
|
@Singleton
|
||||||
public final class LanguageManager {
|
public final class LanguageManager {
|
||||||
private final Map<String, Properties> localeMappings = new HashMap<>();
|
private final Map<String, Properties> localeMappings = new HashMap<>();
|
||||||
private final FloodgateConfigHolder configHolder;
|
|
||||||
private final FloodgateLogger logger;
|
@Inject private FloodgateConfig config;
|
||||||
|
@Inject private FloodgateLogger logger;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The locale used in console and as a fallback
|
* The locale used in console and as a fallback
|
||||||
@@ -71,24 +68,15 @@ public final class LanguageManager {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean isLoaded() {
|
|
||||||
return logger != null && defaultLocale != null;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Tries to load the log's locale file once a string has been requested
|
* Tries to load the log's locale file once a string has been requested
|
||||||
*/
|
*/
|
||||||
|
@Inject
|
||||||
private void init() {
|
private void init() {
|
||||||
if (!loadLocale("en_US")) {// Fallback
|
if (!loadLocale("en_US")) {// Fallback
|
||||||
logger.error("Failed to load the fallback language. This will likely cause errors!");
|
logger.error("Failed to load the fallback language. This will likely cause errors!");
|
||||||
}
|
}
|
||||||
|
|
||||||
FloodgateConfig config = configHolder.get();
|
|
||||||
if (config == null) {
|
|
||||||
// :thonk:
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
defaultLocale = formatLocale(config.getDefaultLocale());
|
defaultLocale = formatLocale(config.getDefaultLocale());
|
||||||
|
|
||||||
if (isValidLanguage(defaultLocale)) {
|
if (isValidLanguage(defaultLocale)) {
|
||||||
@@ -125,21 +113,11 @@ public final class LanguageManager {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
InputStream localeStream = LanguageManager.class.getClassLoader().getResourceAsStream(
|
Properties properties =
|
||||||
"languages/texts/" + formatLocale + ".properties");
|
Utils.readProperties("languages/texts/" + formatLocale + ".properties");
|
||||||
|
|
||||||
// load the locale
|
if (properties != null) {
|
||||||
if (localeStream != null) {
|
localeMappings.put(formatLocale, properties);
|
||||||
Properties localeProp = new Properties();
|
|
||||||
|
|
||||||
try (Reader reader = new InputStreamReader(localeStream, StandardCharsets.UTF_8)) {
|
|
||||||
localeProp.load(reader);
|
|
||||||
} catch (Exception e) {
|
|
||||||
throw new AssertionError("Failed to load Floodgate locale", e);
|
|
||||||
}
|
|
||||||
|
|
||||||
// insert the locale into the mappings
|
|
||||||
localeMappings.put(formatLocale, localeProp);
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -167,14 +145,6 @@ public final class LanguageManager {
|
|||||||
* @return translated string or "key arg1, arg2 (etc.)" if it was not found in the given locale
|
* @return translated string or "key arg1, arg2 (etc.)" if it was not found in the given locale
|
||||||
*/
|
*/
|
||||||
public String getString(String key, String locale, Object... values) {
|
public String getString(String key, String locale, Object... values) {
|
||||||
if (!isLoaded()) {
|
|
||||||
init();
|
|
||||||
// we can skip everything if the LanguageManager can't be loaded yet
|
|
||||||
if (!isLoaded()) {
|
|
||||||
return formatNotFound(key, values);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Properties properties = localeMappings.get(locale);
|
Properties properties = localeMappings.get(locale);
|
||||||
String formatString = null;
|
String formatString = null;
|
||||||
|
|
||||||
|
|||||||
@@ -26,24 +26,29 @@
|
|||||||
package org.geysermc.floodgate.util;
|
package org.geysermc.floodgate.util;
|
||||||
|
|
||||||
import com.google.inject.Inject;
|
import com.google.inject.Inject;
|
||||||
|
import com.google.inject.name.Named;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.Locale;
|
import java.util.Locale;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.regex.Matcher;
|
import java.util.regex.Matcher;
|
||||||
import java.util.regex.Pattern;
|
import java.util.regex.Pattern;
|
||||||
import javax.inject.Named;
|
|
||||||
import org.bstats.MetricsBase;
|
import org.bstats.MetricsBase;
|
||||||
import org.bstats.charts.DrilldownPie;
|
import org.bstats.charts.DrilldownPie;
|
||||||
import org.bstats.charts.SimplePie;
|
import org.bstats.charts.SimplePie;
|
||||||
import org.bstats.charts.SingleLineChart;
|
import org.bstats.charts.SingleLineChart;
|
||||||
import org.bstats.json.JsonObjectBuilder;
|
import org.bstats.json.JsonObjectBuilder;
|
||||||
|
import org.geysermc.event.Listener;
|
||||||
|
import org.geysermc.event.subscribe.Subscribe;
|
||||||
import org.geysermc.floodgate.api.FloodgateApi;
|
import org.geysermc.floodgate.api.FloodgateApi;
|
||||||
import org.geysermc.floodgate.api.logger.FloodgateLogger;
|
import org.geysermc.floodgate.api.logger.FloodgateLogger;
|
||||||
import org.geysermc.floodgate.config.FloodgateConfig;
|
import org.geysermc.floodgate.config.FloodgateConfig;
|
||||||
import org.geysermc.floodgate.config.FloodgateConfig.MetricsConfig;
|
import org.geysermc.floodgate.config.FloodgateConfig.MetricsConfig;
|
||||||
|
import org.geysermc.floodgate.event.lifecycle.ShutdownEvent;
|
||||||
import org.geysermc.floodgate.platform.util.PlatformUtils;
|
import org.geysermc.floodgate.platform.util.PlatformUtils;
|
||||||
|
|
||||||
|
@Listener
|
||||||
|
@AutoBind
|
||||||
public final class Metrics {
|
public final class Metrics {
|
||||||
private final MetricsBase metricsBase;
|
private final MetricsBase metricsBase;
|
||||||
|
|
||||||
@@ -144,4 +149,9 @@ public final class Metrics {
|
|||||||
builder.appendField("osVersion", System.getProperty("os.version"));
|
builder.appendField("osVersion", System.getProperty("os.version"));
|
||||||
builder.appendField("coreCount", Runtime.getRuntime().availableProcessors());
|
builder.appendField("coreCount", Runtime.getRuntime().availableProcessors());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Subscribe
|
||||||
|
public void onShutdown(ShutdownEvent ignored) {
|
||||||
|
metricsBase.shutdown();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,109 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2019-2022 GeyserMC. http://geysermc.org
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
* of this software and associated documentation files (the "Software"), to deal
|
||||||
|
* in the Software without restriction, including without limitation the rights
|
||||||
|
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
* copies of the Software, and to permit persons to whom the Software is
|
||||||
|
* furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in
|
||||||
|
* all copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
|
* THE SOFTWARE.
|
||||||
|
*
|
||||||
|
* @author GeyserMC
|
||||||
|
* @link https://github.com/GeyserMC/Floodgate
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.geysermc.floodgate.util;
|
||||||
|
|
||||||
|
import com.google.inject.Inject;
|
||||||
|
import com.google.inject.name.Named;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.concurrent.ScheduledExecutorService;
|
||||||
|
import java.util.concurrent.TimeUnit;
|
||||||
|
import org.geysermc.event.Listener;
|
||||||
|
import org.geysermc.event.subscribe.Subscribe;
|
||||||
|
import org.geysermc.floodgate.api.logger.FloodgateLogger;
|
||||||
|
import org.geysermc.floodgate.config.FloodgateConfig;
|
||||||
|
import org.geysermc.floodgate.event.lifecycle.PostEnableEvent;
|
||||||
|
|
||||||
|
@AutoBind
|
||||||
|
@Listener
|
||||||
|
public final class PostEnableMessages {
|
||||||
|
private final List<String> messages = new ArrayList<>();
|
||||||
|
|
||||||
|
@Inject private FloodgateConfig config;
|
||||||
|
@Inject private FloodgateLogger logger;
|
||||||
|
@Inject
|
||||||
|
@Named("commonScheduledPool")
|
||||||
|
private ScheduledExecutorService executorService;
|
||||||
|
|
||||||
|
public void add(String[] message, Object... args) {
|
||||||
|
StringBuilder builder = new StringBuilder();
|
||||||
|
|
||||||
|
builder.append("\n**********************************\n");
|
||||||
|
for (String part : message) {
|
||||||
|
builder.append("* ").append(part).append('\n');
|
||||||
|
}
|
||||||
|
builder.append("**********************************");
|
||||||
|
|
||||||
|
messages.add(MessageFormatter.format(builder.toString(), args));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
private void init() {
|
||||||
|
registerPrefixMessages();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void registerPrefixMessages() {
|
||||||
|
String prefix = config.getRawUsernamePrefix();
|
||||||
|
|
||||||
|
if (prefix.isEmpty()) {
|
||||||
|
add(new String[]{
|
||||||
|
"You specified an empty prefix in your Floodgate config for Bedrock players!",
|
||||||
|
"Should a Java player join and a Bedrock player join with the same username, unwanted results and conflicts will happen!",
|
||||||
|
"We strongly recommend using . as the prefix, but other alternatives that will not conflict include: +, - and *"
|
||||||
|
});
|
||||||
|
} else if (!Utils.isUniquePrefix(prefix)) {
|
||||||
|
add(new String[]{
|
||||||
|
"The prefix you entered in your Floodgate config ({}) could lead to username conflicts!",
|
||||||
|
"Should a Java player join with the username {}Notch, and a Bedrock player join as Notch (who will be given the name {}Notch), unwanted results will happen!",
|
||||||
|
"We strongly recommend using . as the prefix, but other alternatives that will not conflict include: +, - and *"
|
||||||
|
}, prefix, prefix, prefix, prefix);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (prefix.length() >= 16) {
|
||||||
|
add(new String[]{
|
||||||
|
"The prefix you entered in your Floodgate config ({}) is longer than a Java username can be!",
|
||||||
|
"Because of this, we reset the prefix to the default Floodgate prefix (.)"
|
||||||
|
}, prefix);
|
||||||
|
} else if (prefix.length() > 2) {
|
||||||
|
// we only have to warn them if we haven't replaced the prefix
|
||||||
|
add(new String[]{
|
||||||
|
"The prefix you entered in your Floodgate config ({}) is long! ({} characters)",
|
||||||
|
"A prefix is there to prevent username conflicts. However, a long prefix makes the chance of username conflicts higher.",
|
||||||
|
"We strongly recommend using . as the prefix, but other alternatives that will not conflict include: +, - and *"
|
||||||
|
}, prefix, prefix.length());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Subscribe
|
||||||
|
public void onPostEnable(PostEnableEvent ignored) {
|
||||||
|
// normally proxies don't have a lot of plugins, so proxies don't need to sleep as long
|
||||||
|
executorService.schedule(
|
||||||
|
() -> messages.forEach(logger::warn),
|
||||||
|
config.isProxy() ? 2 : 5,
|
||||||
|
TimeUnit.SECONDS
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,65 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (c) 2019-2022 GeyserMC. http://geysermc.org
|
|
||||||
*
|
|
||||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
||||||
* of this software and associated documentation files (the "Software"), to deal
|
|
||||||
* in the Software without restriction, including without limitation the rights
|
|
||||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
||||||
* copies of the Software, and to permit persons to whom the Software is
|
|
||||||
* furnished to do so, subject to the following conditions:
|
|
||||||
*
|
|
||||||
* The above copyright notice and this permission notice shall be included in
|
|
||||||
* all copies or substantial portions of the Software.
|
|
||||||
*
|
|
||||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
||||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
||||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
||||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
||||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
||||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
|
||||||
* THE SOFTWARE.
|
|
||||||
*
|
|
||||||
* @author GeyserMC
|
|
||||||
* @link https://github.com/GeyserMC/Floodgate
|
|
||||||
*/
|
|
||||||
|
|
||||||
package org.geysermc.floodgate.util;
|
|
||||||
|
|
||||||
import org.geysermc.floodgate.api.logger.FloodgateLogger;
|
|
||||||
import org.geysermc.floodgate.config.FloodgateConfig;
|
|
||||||
|
|
||||||
public final class PrefixCheckTask {
|
|
||||||
public static void checkAndExecuteDelayed(FloodgateConfig config, FloodgateLogger logger) {
|
|
||||||
if (Utils.isUniquePrefix(config.getUsernamePrefix())) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
new Thread(() -> {
|
|
||||||
// normally proxies don't have a lot of plugins, so proxies don't need to sleep as long
|
|
||||||
try {
|
|
||||||
Thread.sleep(config.isProxy() ? 1000 : 2000);
|
|
||||||
} catch (InterruptedException ignored) {
|
|
||||||
}
|
|
||||||
|
|
||||||
if (config.getUsernamePrefix().isEmpty()) {
|
|
||||||
logger.warn("\n" +
|
|
||||||
"**********************************\n" +
|
|
||||||
"* You specified an empty prefix in your Floodgate config for Bedrock players!\n" +
|
|
||||||
"* Should a Java player join and a Bedrock player join with the same username, unwanted results and conflicts will happen!\n" +
|
|
||||||
"* We strongly recommend using . as the prefix, but other alternatives that will not conflict include: +, - and *\n" +
|
|
||||||
"**********************************");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
logger.warn(
|
|
||||||
"\n" +
|
|
||||||
"**********************************\n" +
|
|
||||||
"* The prefix you entered in your Floodgate config ({}) could lead to username conflicts!\n" +
|
|
||||||
"* Should a Java player join with the username {}Notch, and a Bedrock player join as Notch (who will be given the name {}Notch), unwanted results will happen!\n" +
|
|
||||||
"* We strongly recommend using . as the prefix, but other alternatives that will not conflict include: +, - and *\n" +
|
|
||||||
"**********************************",
|
|
||||||
config.getUsernamePrefix(), config.getUsernamePrefix(),
|
|
||||||
config.getUsernamePrefix(), config.getUsernamePrefix());
|
|
||||||
}).start();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -287,7 +287,7 @@ public final class ReflectionUtils {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the value of a field and cast it to <T>.
|
* Get the value of a field and cast it to T.
|
||||||
*
|
*
|
||||||
* @param instance the instance to get the value from
|
* @param instance the instance to get the value from
|
||||||
* @param field the field to get the value from
|
* @param field the field to get the value from
|
||||||
@@ -301,7 +301,7 @@ public final class ReflectionUtils {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the value of a field and cast it to <T>.
|
* Get the value of a field and cast it to T.
|
||||||
*
|
*
|
||||||
* @param instance the instance to get the value from
|
* @param instance the instance to get the value from
|
||||||
* @param fieldName the field to get the value from
|
* @param fieldName the field to get the value from
|
||||||
@@ -424,7 +424,7 @@ public final class ReflectionUtils {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Nullable
|
@Nullable
|
||||||
public static Method getMethod(
|
public static Method getMethodThatReturns(
|
||||||
Class<?> clazz,
|
Class<?> clazz,
|
||||||
Class<?> returnType,
|
Class<?> returnType,
|
||||||
boolean declared,
|
boolean declared,
|
||||||
|
|||||||
@@ -33,21 +33,19 @@ import java.io.IOException;
|
|||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
import java.io.InputStreamReader;
|
import java.io.InputStreamReader;
|
||||||
import java.io.PrintWriter;
|
import java.io.PrintWriter;
|
||||||
import java.io.Reader;
|
|
||||||
import java.io.StringWriter;
|
import java.io.StringWriter;
|
||||||
import java.nio.charset.Charset;
|
import java.lang.annotation.Annotation;
|
||||||
import java.nio.charset.CharsetDecoder;
|
|
||||||
import java.nio.charset.StandardCharsets;
|
import java.nio.charset.StandardCharsets;
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.Locale;
|
import java.util.Locale;
|
||||||
import java.util.Properties;
|
import java.util.Properties;
|
||||||
|
import java.util.Set;
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
import java.util.concurrent.CompletableFuture;
|
import java.util.concurrent.CompletableFuture;
|
||||||
import java.util.regex.Pattern;
|
import java.util.regex.Pattern;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
public class Utils {
|
public class Utils {
|
||||||
private static final Pattern NON_UNIQUE_PREFIX = Pattern.compile("^[a-zA-Z0-9_]{0,16}$");
|
private static final Pattern NON_UNIQUE_PREFIX = Pattern.compile("^\\w{0,16}$");
|
||||||
private static final Pattern DATABASE_NAME = Pattern.compile(Constants.DATABASE_NAME_FORMAT);
|
private static final Pattern DATABASE_NAME = Pattern.compile(Constants.DATABASE_NAME_FORMAT);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -66,33 +64,21 @@ public class Utils {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static List<String> readAllLines(String resourcePath) throws IOException {
|
/**
|
||||||
InputStream stream = Utils.class.getClassLoader().getResourceAsStream(resourcePath);
|
* Reads a properties resource file
|
||||||
try (BufferedReader reader = newBufferedReader(stream, StandardCharsets.UTF_8)) {
|
* @param resourceFile the resource file to read
|
||||||
List<String> result = new ArrayList<>();
|
* @return the properties file if the resource exists, otherwise null
|
||||||
for (; ; ) {
|
* @throws AssertionError if something went wrong while readin the resource file
|
||||||
String line = reader.readLine();
|
*/
|
||||||
if (line == null) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
result.add(line);
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static BufferedReader newBufferedReader(InputStream inputStream, Charset charset) {
|
|
||||||
CharsetDecoder decoder = charset.newDecoder();
|
|
||||||
Reader reader = new InputStreamReader(inputStream, decoder);
|
|
||||||
return new BufferedReader(reader);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static Properties readProperties(String resourceFile) {
|
public static Properties readProperties(String resourceFile) {
|
||||||
Properties properties = new Properties();
|
Properties properties = new Properties();
|
||||||
try (InputStream is = Utils.class.getClassLoader().getResourceAsStream(resourceFile)) {
|
try (InputStream is = Utils.class.getClassLoader().getResourceAsStream(resourceFile)) {
|
||||||
properties.load(is);
|
if (is == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
properties.load(new InputStreamReader(is, StandardCharsets.UTF_8));
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
e.printStackTrace();
|
throw new AssertionError("Failed to read properties file", e);
|
||||||
}
|
}
|
||||||
return properties;
|
return properties;
|
||||||
}
|
}
|
||||||
@@ -151,4 +137,42 @@ public class Utils {
|
|||||||
future.completeExceptionally(ex);
|
future.completeExceptionally(ex);
|
||||||
return future;
|
return future;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a set of all the classes that are annotated by a given annotation.
|
||||||
|
* Keep in mind that these are from a set of generated annotations generated
|
||||||
|
* at compile time by the annotation processor, meaning that arbitrary annotations
|
||||||
|
* cannot be passed into this method and expected to get a set of classes back.
|
||||||
|
*
|
||||||
|
* @param annotationClass the annotation class
|
||||||
|
* @return a set of all the classes annotated by the given annotation
|
||||||
|
*/
|
||||||
|
public static Set<Class<?>> getGeneratedClassesForAnnotation(Class<? extends Annotation> annotationClass) {
|
||||||
|
return getGeneratedClassesForAnnotation(annotationClass.getName());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a set of all the classes that are annotated by a given annotation.
|
||||||
|
* Keep in mind that these are from a set of generated annotations generated
|
||||||
|
* at compile time by the annotation processor, meaning that arbitrary annotations
|
||||||
|
* cannot be passed into this method and expected to have a set of classes
|
||||||
|
* returned back.
|
||||||
|
*
|
||||||
|
* @param input the fully qualified name of the annotation
|
||||||
|
* @return a set of all the classes annotated by the given annotation
|
||||||
|
*/
|
||||||
|
public static Set<Class<?>> getGeneratedClassesForAnnotation(String input) {
|
||||||
|
try (InputStream annotatedClass = Utils.class.getClassLoader().getResourceAsStream(input);
|
||||||
|
BufferedReader reader = new BufferedReader(new InputStreamReader(annotatedClass))) {
|
||||||
|
return reader.lines().map(className -> {
|
||||||
|
try {
|
||||||
|
return Class.forName(className);
|
||||||
|
} catch (ClassNotFoundException ex) {
|
||||||
|
throw new RuntimeException("Failed to find class for annotation " + input, ex);
|
||||||
|
}
|
||||||
|
}).collect(Collectors.toSet());
|
||||||
|
} catch (IOException e) {
|
||||||
|
throw new RuntimeException(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Submodule core/src/main/resources/languages updated: 38cb4a52df...204f4fe492
@@ -26,12 +26,12 @@
|
|||||||
package org.geysermc.floodgate.util;
|
package org.geysermc.floodgate.util;
|
||||||
|
|
||||||
public final class Constants {
|
public final class Constants {
|
||||||
public static final String VERSION = "${floodgateVersion}";
|
public static final String VERSION = "@floodgateVersion@";
|
||||||
public static final int BUILD_NUMBER = Integer.parseInt("${buildNumber}");
|
public static final int BUILD_NUMBER = Integer.parseInt("@buildNumber@");
|
||||||
public static final String GIT_BRANCH = "${branch}";
|
public static final String GIT_BRANCH = "@branch@";
|
||||||
public static final int METRICS_ID = 14649;
|
public static final int METRICS_ID = 14649;
|
||||||
|
|
||||||
public static final char COLOR_CHAR = '§';
|
public static final char COLOR_CHAR = '\u00A7';
|
||||||
|
|
||||||
public static final boolean DEBUG_MODE = false;
|
public static final boolean DEBUG_MODE = false;
|
||||||
public static final boolean PRINT_ALL_PACKETS = false;
|
public static final boolean PRINT_ALL_PACKETS = false;
|
||||||
4
database/mysql/.editorconfig
Normal file
4
database/mysql/.editorconfig
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
[*]
|
||||||
|
indent_size = 2
|
||||||
|
tab_width = 2
|
||||||
|
ij_continuation_indent_size = 4
|
||||||
@@ -1,10 +1,17 @@
|
|||||||
val mariadbClientVersion = "2.7.4"
|
|
||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
provided(projects.core)
|
provided(projects.core)
|
||||||
implementation("org.mariadb.jdbc", "mariadb-java-client" , mariadbClientVersion)
|
|
||||||
|
// update HikariCP when we move to Java 11+
|
||||||
|
implementation("com.zaxxer", "HikariCP", "4.0.3")
|
||||||
|
|
||||||
|
implementation("com.mysql", "mysql-connector-j", "8.0.32") {
|
||||||
|
exclude("com.google.protobuf", "protobuf-java")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
description = "The Floodgate database extension for MySQL"
|
description = "The Floodgate database extension for MySQL"
|
||||||
|
|
||||||
relocate("org.mariadb")
|
// relocate everything from mysql-connector-j and HikariCP
|
||||||
|
relocate("com.mysql")
|
||||||
|
relocate("com.zaxxer.hikari")
|
||||||
|
relocate("org.slf4j")
|
||||||
|
|||||||
@@ -25,6 +25,8 @@
|
|||||||
|
|
||||||
package org.geysermc.floodgate.database;
|
package org.geysermc.floodgate.database;
|
||||||
|
|
||||||
|
import com.zaxxer.hikari.HikariConfig;
|
||||||
|
import com.zaxxer.hikari.HikariDataSource;
|
||||||
import java.nio.ByteBuffer;
|
import java.nio.ByteBuffer;
|
||||||
import java.nio.ByteOrder;
|
import java.nio.ByteOrder;
|
||||||
import java.sql.Connection;
|
import java.sql.Connection;
|
||||||
@@ -43,41 +45,28 @@ import org.geysermc.floodgate.database.config.MysqlConfig;
|
|||||||
import org.geysermc.floodgate.link.CommonPlayerLink;
|
import org.geysermc.floodgate.link.CommonPlayerLink;
|
||||||
import org.geysermc.floodgate.link.LinkRequestImpl;
|
import org.geysermc.floodgate.link.LinkRequestImpl;
|
||||||
import org.geysermc.floodgate.util.LinkedPlayer;
|
import org.geysermc.floodgate.util.LinkedPlayer;
|
||||||
import org.mariadb.jdbc.MariaDbPoolDataSource;
|
|
||||||
|
|
||||||
public class MysqlDatabase extends CommonPlayerLink {
|
public class MysqlDatabase extends CommonPlayerLink {
|
||||||
private MariaDbPoolDataSource pool;
|
private HikariDataSource dataSource;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void load() {
|
public void load() {
|
||||||
getLogger().info("Connecting to a MySQL-like database...");
|
getLogger().info("Connecting to a MySQL-like database...");
|
||||||
try {
|
try {
|
||||||
Class.forName("org.mariadb.jdbc.Driver");
|
MysqlConfig config = getConfig(MysqlConfig.class);
|
||||||
MysqlConfig databaseconfig = getConfig(MysqlConfig.class);
|
|
||||||
|
|
||||||
pool = new MariaDbPoolDataSource();
|
HikariConfig hikariConfig = new HikariConfig();
|
||||||
|
hikariConfig.setDriverClassName("com.mysql.cj.jdbc.Driver");
|
||||||
|
hikariConfig.setJdbcUrl("jdbc:mysql://" + config.getHostname() + "/" + config.getDatabase());
|
||||||
|
hikariConfig.setUsername(config.getUsername());
|
||||||
|
hikariConfig.setPassword(config.getPassword());
|
||||||
|
hikariConfig.setPoolName("floodgate-linking-mysql");
|
||||||
|
hikariConfig.setMinimumIdle(5);
|
||||||
|
hikariConfig.setMaximumPoolSize(10);
|
||||||
|
|
||||||
String hostname = databaseconfig.getHostname();
|
dataSource = new HikariDataSource(hikariConfig);
|
||||||
if (hostname.contains(":")) {
|
|
||||||
String[] split = hostname.split(":");
|
|
||||||
|
|
||||||
pool.setServerName(split[0]);
|
try (Connection connection = dataSource.getConnection()) {
|
||||||
try {
|
|
||||||
pool.setPortNumber(Integer.parseInt(split[1]));
|
|
||||||
} catch (NumberFormatException exception) {
|
|
||||||
getLogger().info("{} is not a valid port! Will use the default port", split[1]);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
pool.setServerName(hostname);
|
|
||||||
}
|
|
||||||
|
|
||||||
pool.setUser(databaseconfig.getUsername());
|
|
||||||
pool.setPassword(databaseconfig.getPassword());
|
|
||||||
pool.setDatabaseName(databaseconfig.getDatabase());
|
|
||||||
pool.setMinPoolSize(2);
|
|
||||||
pool.setMaxPoolSize(10);
|
|
||||||
|
|
||||||
try (Connection connection = pool.getConnection()) {
|
|
||||||
try (Statement statement = connection.createStatement()) {
|
try (Statement statement = connection.createStatement()) {
|
||||||
statement.executeUpdate(
|
statement.executeUpdate(
|
||||||
"CREATE TABLE IF NOT EXISTS `LinkedPlayers` ( " +
|
"CREATE TABLE IF NOT EXISTS `LinkedPlayers` ( " +
|
||||||
@@ -100,8 +89,6 @@ public class MysqlDatabase extends CommonPlayerLink {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
getLogger().info("Connected to MySQL-like database.");
|
getLogger().info("Connected to MySQL-like database.");
|
||||||
} catch (ClassNotFoundException exception) {
|
|
||||||
getLogger().error("The required class to load the MySQL database wasn't found");
|
|
||||||
} catch (SQLException exception) {
|
} catch (SQLException exception) {
|
||||||
getLogger().error("Error while loading database", exception);
|
getLogger().error("Error while loading database", exception);
|
||||||
}
|
}
|
||||||
@@ -110,14 +97,14 @@ public class MysqlDatabase extends CommonPlayerLink {
|
|||||||
@Override
|
@Override
|
||||||
public void stop() {
|
public void stop() {
|
||||||
super.stop();
|
super.stop();
|
||||||
pool.close();
|
dataSource.close();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@NonNull
|
@NonNull
|
||||||
public CompletableFuture<LinkedPlayer> getLinkedPlayer(@NonNull UUID bedrockId) {
|
public CompletableFuture<LinkedPlayer> getLinkedPlayer(@NonNull UUID bedrockId) {
|
||||||
return CompletableFuture.supplyAsync(() -> {
|
return CompletableFuture.supplyAsync(() -> {
|
||||||
try (Connection connection = pool.getConnection()) {
|
try (Connection connection = dataSource.getConnection()) {
|
||||||
try (PreparedStatement query = connection.prepareStatement(
|
try (PreparedStatement query = connection.prepareStatement(
|
||||||
"SELECT * FROM `LinkedPlayers` WHERE `bedrockId` = ?"
|
"SELECT * FROM `LinkedPlayers` WHERE `bedrockId` = ?"
|
||||||
)) {
|
)) {
|
||||||
@@ -142,7 +129,7 @@ public class MysqlDatabase extends CommonPlayerLink {
|
|||||||
@NonNull
|
@NonNull
|
||||||
public CompletableFuture<Boolean> isLinkedPlayer(@NonNull UUID playerId) {
|
public CompletableFuture<Boolean> isLinkedPlayer(@NonNull UUID playerId) {
|
||||||
return CompletableFuture.supplyAsync(() -> {
|
return CompletableFuture.supplyAsync(() -> {
|
||||||
try (Connection connection = pool.getConnection()) {
|
try (Connection connection = dataSource.getConnection()) {
|
||||||
try (PreparedStatement query = connection.prepareStatement(
|
try (PreparedStatement query = connection.prepareStatement(
|
||||||
"SELECT * FROM `LinkedPlayers` WHERE `bedrockId` = ? OR `javaUniqueId` = ?"
|
"SELECT * FROM `LinkedPlayers` WHERE `bedrockId` = ? OR `javaUniqueId` = ?"
|
||||||
)) {
|
)) {
|
||||||
@@ -174,7 +161,7 @@ public class MysqlDatabase extends CommonPlayerLink {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void linkPlayer0(UUID bedrockId, UUID javaId, String javaUsername) {
|
private void linkPlayer0(UUID bedrockId, UUID javaId, String javaUsername) {
|
||||||
try (Connection connection = pool.getConnection()) {
|
try (Connection connection = dataSource.getConnection()) {
|
||||||
try (PreparedStatement query = connection.prepareStatement(
|
try (PreparedStatement query = connection.prepareStatement(
|
||||||
"INSERT INTO `LinkedPlayers` VALUES (?, ?, ?) ON DUPLICATE KEY UPDATE " +
|
"INSERT INTO `LinkedPlayers` VALUES (?, ?, ?) ON DUPLICATE KEY UPDATE " +
|
||||||
"`javaUniqueId`=VALUES(`javaUniqueId`), " +
|
"`javaUniqueId`=VALUES(`javaUniqueId`), " +
|
||||||
@@ -195,7 +182,7 @@ public class MysqlDatabase extends CommonPlayerLink {
|
|||||||
@NonNull
|
@NonNull
|
||||||
public CompletableFuture<Void> unlinkPlayer(@NonNull UUID javaId) {
|
public CompletableFuture<Void> unlinkPlayer(@NonNull UUID javaId) {
|
||||||
return CompletableFuture.runAsync(() -> {
|
return CompletableFuture.runAsync(() -> {
|
||||||
try (Connection connection = pool.getConnection()) {
|
try (Connection connection = dataSource.getConnection()) {
|
||||||
try (PreparedStatement query = connection.prepareStatement(
|
try (PreparedStatement query = connection.prepareStatement(
|
||||||
"DELETE FROM `LinkedPlayers` WHERE `javaUniqueId` = ? OR `bedrockId` = ?"
|
"DELETE FROM `LinkedPlayers` WHERE `javaUniqueId` = ? OR `bedrockId` = ?"
|
||||||
)) {
|
)) {
|
||||||
@@ -216,7 +203,8 @@ public class MysqlDatabase extends CommonPlayerLink {
|
|||||||
public CompletableFuture<String> createLinkRequest(
|
public CompletableFuture<String> createLinkRequest(
|
||||||
@NonNull UUID javaId,
|
@NonNull UUID javaId,
|
||||||
@NonNull String javaUsername,
|
@NonNull String javaUsername,
|
||||||
@NonNull String bedrockUsername) {
|
@NonNull String bedrockUsername
|
||||||
|
) {
|
||||||
return CompletableFuture.supplyAsync(() -> {
|
return CompletableFuture.supplyAsync(() -> {
|
||||||
String linkCode = createCode();
|
String linkCode = createCode();
|
||||||
|
|
||||||
@@ -230,8 +218,9 @@ public class MysqlDatabase extends CommonPlayerLink {
|
|||||||
String javaUsername,
|
String javaUsername,
|
||||||
UUID javaId,
|
UUID javaId,
|
||||||
String linkCode,
|
String linkCode,
|
||||||
String bedrockUsername) {
|
String bedrockUsername
|
||||||
try (Connection connection = pool.getConnection()) {
|
) {
|
||||||
|
try (Connection connection = dataSource.getConnection()) {
|
||||||
try (PreparedStatement query = connection.prepareStatement(
|
try (PreparedStatement query = connection.prepareStatement(
|
||||||
"INSERT INTO `LinkedPlayersRequest` VALUES (?, ?, ?, ?, ?) " +
|
"INSERT INTO `LinkedPlayersRequest` VALUES (?, ?, ?, ?, ?) " +
|
||||||
"ON DUPLICATE KEY UPDATE " +
|
"ON DUPLICATE KEY UPDATE " +
|
||||||
@@ -254,7 +243,7 @@ public class MysqlDatabase extends CommonPlayerLink {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void removeLinkRequest(String javaUsername) {
|
private void removeLinkRequest(String javaUsername) {
|
||||||
try (Connection connection = pool.getConnection()) {
|
try (Connection connection = dataSource.getConnection()) {
|
||||||
try (PreparedStatement query = connection.prepareStatement(
|
try (PreparedStatement query = connection.prepareStatement(
|
||||||
"DELETE FROM `LinkedPlayersRequest` WHERE `javaUsername` = ?"
|
"DELETE FROM `LinkedPlayersRequest` WHERE `javaUsername` = ?"
|
||||||
)) {
|
)) {
|
||||||
@@ -272,7 +261,8 @@ public class MysqlDatabase extends CommonPlayerLink {
|
|||||||
@NonNull UUID bedrockId,
|
@NonNull UUID bedrockId,
|
||||||
@NonNull String javaUsername,
|
@NonNull String javaUsername,
|
||||||
@NonNull String bedrockUsername,
|
@NonNull String bedrockUsername,
|
||||||
@NonNull String code) {
|
@NonNull String code
|
||||||
|
) {
|
||||||
return CompletableFuture.supplyAsync(() -> {
|
return CompletableFuture.supplyAsync(() -> {
|
||||||
LinkRequest request = getLinkRequest0(javaUsername);
|
LinkRequest request = getLinkRequest0(javaUsername);
|
||||||
|
|
||||||
@@ -297,7 +287,7 @@ public class MysqlDatabase extends CommonPlayerLink {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private LinkRequest getLinkRequest0(String javaUsername) {
|
private LinkRequest getLinkRequest0(String javaUsername) {
|
||||||
try (Connection connection = pool.getConnection()) {
|
try (Connection connection = dataSource.getConnection()) {
|
||||||
try (PreparedStatement query = connection.prepareStatement(
|
try (PreparedStatement query = connection.prepareStatement(
|
||||||
"SELECT * FROM `LinkedPlayersRequest` WHERE `javaUsername` = ?"
|
"SELECT * FROM `LinkedPlayersRequest` WHERE `javaUsername` = ?"
|
||||||
)) {
|
)) {
|
||||||
@@ -322,7 +312,7 @@ public class MysqlDatabase extends CommonPlayerLink {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public void cleanLinkRequests() {
|
public void cleanLinkRequests() {
|
||||||
try (Connection connection = pool.getConnection()) {
|
try (Connection connection = dataSource.getConnection()) {
|
||||||
try (PreparedStatement query = connection.prepareStatement(
|
try (PreparedStatement query = connection.prepareStatement(
|
||||||
"DELETE FROM `LinkedPlayersRequest` WHERE `requestTime` < ?"
|
"DELETE FROM `LinkedPlayersRequest` WHERE `requestTime` < ?"
|
||||||
)) {
|
)) {
|
||||||
@@ -347,5 +337,4 @@ public class MysqlDatabase extends CommonPlayerLink {
|
|||||||
ByteBuffer buf = ByteBuffer.wrap(uuidBytes);
|
ByteBuffer buf = ByteBuffer.wrap(uuidBytes);
|
||||||
return new UUID(buf.getLong(), buf.getLong());
|
return new UUID(buf.getLong(), buf.getLong());
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,3 +1,5 @@
|
|||||||
org.gradle.configureondemand=true
|
org.gradle.configureondemand=true
|
||||||
org.gradle.caching=true
|
org.gradle.caching=true
|
||||||
org.gradle.parallel=true
|
org.gradle.parallel=true
|
||||||
|
|
||||||
|
version=2.2.2-SNAPSHOT
|
||||||
2
gradle/wrapper/gradle-wrapper.properties
vendored
2
gradle/wrapper/gradle-wrapper.properties
vendored
@@ -1,5 +1,5 @@
|
|||||||
distributionBase=GRADLE_USER_HOME
|
distributionBase=GRADLE_USER_HOME
|
||||||
distributionPath=wrapper/dists
|
distributionPath=wrapper/dists
|
||||||
distributionUrl=https\://services.gradle.org/distributions/gradle-7.3.3-bin.zip
|
distributionUrl=https\://services.gradle.org/distributions/gradle-7.6-bin.zip
|
||||||
zipStoreBase=GRADLE_USER_HOME
|
zipStoreBase=GRADLE_USER_HOME
|
||||||
zipStorePath=wrapper/dists
|
zipStorePath=wrapper/dists
|
||||||
|
|||||||
10
gradlew
vendored
10
gradlew
vendored
@@ -1,7 +1,7 @@
|
|||||||
#!/bin/sh
|
#!/bin/sh
|
||||||
|
|
||||||
#
|
#
|
||||||
# Copyright © 2015-2021 the original authors.
|
# Copyright <EFBFBD> 2015-2021 the original authors.
|
||||||
#
|
#
|
||||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
# you may not use this file except in compliance with the License.
|
# you may not use this file except in compliance with the License.
|
||||||
@@ -32,10 +32,10 @@
|
|||||||
# Busybox and similar reduced shells will NOT work, because this script
|
# Busybox and similar reduced shells will NOT work, because this script
|
||||||
# requires all of these POSIX shell features:
|
# requires all of these POSIX shell features:
|
||||||
# * functions;
|
# * functions;
|
||||||
# * expansions «$var», «${var}», «${var:-default}», «${var+SET}»,
|
# * expansions <EFBFBD>$var<EFBFBD>, <EFBFBD>${var}<EFBFBD>, <EFBFBD>${var:-default}<EFBFBD>, <EFBFBD>${var+SET}<EFBFBD>,
|
||||||
# «${var#prefix}», «${var%suffix}», and «$( cmd )»;
|
# <EFBFBD>${var#prefix}<EFBFBD>, <EFBFBD>${var%suffix}<EFBFBD>, and <EFBFBD>$( cmd )<EFBFBD>;
|
||||||
# * compound commands having a testable exit status, especially «case»;
|
# * compound commands having a testable exit status, especially <EFBFBD>case<EFBFBD>;
|
||||||
# * various built-in commands including «command», «set», and «ulimit».
|
# * various built-in commands including <EFBFBD>command<EFBFBD>, <EFBFBD>set<EFBFBD>, and <EFBFBD>ulimit<EFBFBD>.
|
||||||
#
|
#
|
||||||
# Important for patching:
|
# Important for patching:
|
||||||
#
|
#
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
@file:Suppress("UnstableApiUsage")
|
||||||
enableFeaturePreview("TYPESAFE_PROJECT_ACCESSORS")
|
enableFeaturePreview("TYPESAFE_PROJECT_ACCESSORS")
|
||||||
|
|
||||||
dependencyResolutionManagement {
|
dependencyResolutionManagement {
|
||||||
@@ -14,7 +15,19 @@ dependencyResolutionManagement {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Paper, Velocity
|
// Paper, Velocity
|
||||||
maven("https://papermc.io/repo/repository/maven-public")
|
// maven("https://repo.papermc.io/repository/maven-releases") {
|
||||||
|
// mavenContent { releasesOnly() }
|
||||||
|
// }
|
||||||
|
// maven("https://repo.papermc.io/repository/maven-snapshots") {
|
||||||
|
// mavenContent { snapshotsOnly() }
|
||||||
|
// }
|
||||||
|
maven("https://repo.papermc.io/repository/maven-public") {
|
||||||
|
content {
|
||||||
|
includeGroupByRegex(
|
||||||
|
"(io\\.papermc\\..*|com\\.destroystokyo\\..*|com\\.velocitypowered)"
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
// Spigot
|
// Spigot
|
||||||
maven("https://hub.spigotmc.org/nexus/content/repositories/snapshots") {
|
maven("https://hub.spigotmc.org/nexus/content/repositories/snapshots") {
|
||||||
mavenContent { snapshotsOnly() }
|
mavenContent { snapshotsOnly() }
|
||||||
@@ -43,7 +56,8 @@ pluginManagement {
|
|||||||
gradlePluginPortal()
|
gradlePluginPortal()
|
||||||
}
|
}
|
||||||
plugins {
|
plugins {
|
||||||
id("net.kyori.blossom") version "1.2.0"
|
id("net.kyori.indra")
|
||||||
|
id("net.kyori.indra.git")
|
||||||
}
|
}
|
||||||
includeBuild("build-logic")
|
includeBuild("build-logic")
|
||||||
}
|
}
|
||||||
@@ -51,6 +65,7 @@ pluginManagement {
|
|||||||
rootProject.name = "floodgate-parent"
|
rootProject.name = "floodgate-parent"
|
||||||
|
|
||||||
include(":api")
|
include(":api")
|
||||||
|
include(":ap")
|
||||||
include(":core")
|
include(":core")
|
||||||
include(":bungee")
|
include(":bungee")
|
||||||
include(":spigot")
|
include(":spigot")
|
||||||
|
|||||||
@@ -27,6 +27,7 @@ package org.geysermc.floodgate;
|
|||||||
|
|
||||||
import com.google.inject.Guice;
|
import com.google.inject.Guice;
|
||||||
import com.google.inject.Injector;
|
import com.google.inject.Injector;
|
||||||
|
import org.bukkit.Bukkit;
|
||||||
import org.bukkit.plugin.java.JavaPlugin;
|
import org.bukkit.plugin.java.JavaPlugin;
|
||||||
import org.geysermc.floodgate.api.handshake.HandshakeHandlers;
|
import org.geysermc.floodgate.api.handshake.HandshakeHandlers;
|
||||||
import org.geysermc.floodgate.api.logger.FloodgateLogger;
|
import org.geysermc.floodgate.api.logger.FloodgateLogger;
|
||||||
@@ -43,7 +44,7 @@ import org.geysermc.floodgate.util.SpigotProtocolSupportHandler;
|
|||||||
import org.geysermc.floodgate.util.SpigotProtocolSupportListener;
|
import org.geysermc.floodgate.util.SpigotProtocolSupportListener;
|
||||||
|
|
||||||
public final class SpigotPlugin extends JavaPlugin {
|
public final class SpigotPlugin extends JavaPlugin {
|
||||||
private SpigotPlatform platform;
|
private FloodgatePlatform platform;
|
||||||
private Injector injector;
|
private Injector injector;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -54,7 +55,7 @@ public final class SpigotPlugin extends JavaPlugin {
|
|||||||
new SpigotPlatformModule(this)
|
new SpigotPlatformModule(this)
|
||||||
);
|
);
|
||||||
|
|
||||||
platform = injector.getInstance(SpigotPlatform.class);
|
platform = injector.getInstance(FloodgatePlatform.class);
|
||||||
|
|
||||||
long endCtm = System.currentTimeMillis();
|
long endCtm = System.currentTimeMillis();
|
||||||
injector.getInstance(FloodgateLogger.class)
|
injector.getInstance(FloodgateLogger.class)
|
||||||
@@ -66,14 +67,18 @@ public final class SpigotPlugin extends JavaPlugin {
|
|||||||
boolean usePaperListener = ReflectionUtils.getClassSilently(
|
boolean usePaperListener = ReflectionUtils.getClassSilently(
|
||||||
"com.destroystokyo.paper.event.profile.PreFillProfileEvent") != null;
|
"com.destroystokyo.paper.event.profile.PreFillProfileEvent") != null;
|
||||||
|
|
||||||
|
try {
|
||||||
platform.enable(
|
platform.enable(
|
||||||
new SpigotCommandModule(this),
|
new SpigotCommandModule(this),
|
||||||
new SpigotAddonModule(),
|
new SpigotAddonModule(),
|
||||||
new PluginMessageModule(),
|
new PluginMessageModule(),
|
||||||
(usePaperListener ? new PaperListenerModule() : new SpigotListenerModule())
|
(usePaperListener ? new PaperListenerModule() : new SpigotListenerModule())
|
||||||
);
|
);
|
||||||
|
} catch (Exception exception) {
|
||||||
|
Bukkit.getPluginManager().disablePlugin(this);
|
||||||
|
throw exception;
|
||||||
|
}
|
||||||
|
|
||||||
//todo add proper support for disabling things on shutdown and enabling this on enable
|
|
||||||
injector.getInstance(HandshakeHandlers.class)
|
injector.getInstance(HandshakeHandlers.class)
|
||||||
.addHandshakeHandler(injector.getInstance(SpigotHandshakeHandler.class));
|
.addHandshakeHandler(injector.getInstance(SpigotHandshakeHandler.class));
|
||||||
|
|
||||||
|
|||||||
@@ -25,25 +25,28 @@
|
|||||||
|
|
||||||
package org.geysermc.floodgate.inject.spigot;
|
package org.geysermc.floodgate.inject.spigot;
|
||||||
|
|
||||||
|
import com.google.inject.Inject;
|
||||||
|
import com.google.inject.Singleton;
|
||||||
import io.netty.channel.Channel;
|
import io.netty.channel.Channel;
|
||||||
import io.netty.channel.ChannelFuture;
|
import io.netty.channel.ChannelFuture;
|
||||||
import io.netty.channel.ChannelHandlerContext;
|
import io.netty.channel.ChannelHandlerContext;
|
||||||
import io.netty.channel.ChannelInboundHandlerAdapter;
|
import io.netty.channel.ChannelInboundHandlerAdapter;
|
||||||
import io.netty.channel.ChannelInitializer;
|
import io.netty.channel.ChannelInitializer;
|
||||||
import java.lang.reflect.Field;
|
import java.lang.reflect.Field;
|
||||||
import java.lang.reflect.InvocationTargetException;
|
|
||||||
import java.lang.reflect.Method;
|
import java.lang.reflect.Method;
|
||||||
import java.lang.reflect.ParameterizedType;
|
import java.lang.reflect.ParameterizedType;
|
||||||
import java.lang.reflect.Type;
|
import java.lang.reflect.Type;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import lombok.Getter;
|
import lombok.Getter;
|
||||||
import lombok.RequiredArgsConstructor;
|
import org.geysermc.floodgate.api.logger.FloodgateLogger;
|
||||||
import org.geysermc.floodgate.inject.CommonPlatformInjector;
|
import org.geysermc.floodgate.inject.CommonPlatformInjector;
|
||||||
import org.geysermc.floodgate.util.ClassNames;
|
import org.geysermc.floodgate.util.ClassNames;
|
||||||
import org.geysermc.floodgate.util.ReflectionUtils;
|
import org.geysermc.floodgate.util.ReflectionUtils;
|
||||||
|
|
||||||
@RequiredArgsConstructor
|
@Singleton
|
||||||
public final class SpigotInjector extends CommonPlatformInjector {
|
public final class SpigotInjector extends CommonPlatformInjector {
|
||||||
|
@Inject private FloodgateLogger logger;
|
||||||
|
|
||||||
private Object serverConnection;
|
private Object serverConnection;
|
||||||
private String injectedFieldName;
|
private String injectedFieldName;
|
||||||
|
|
||||||
@@ -51,12 +54,16 @@ public final class SpigotInjector extends CommonPlatformInjector {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
@SuppressWarnings("SynchronizationOnLocalVariableOrMethodParameter")
|
@SuppressWarnings("SynchronizationOnLocalVariableOrMethodParameter")
|
||||||
public boolean inject() throws Exception {
|
public void inject() throws Exception {
|
||||||
if (isInjected()) {
|
if (isInjected()) {
|
||||||
return true;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
Object serverConnection = getServerConnection();
|
||||||
|
if (serverConnection == null) {
|
||||||
|
throw new RuntimeException("Unable to find server connection");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (getServerConnection() != null) {
|
|
||||||
for (Field field : serverConnection.getClass().getDeclaredFields()) {
|
for (Field field : serverConnection.getClass().getDeclaredFields()) {
|
||||||
if (field.getType() == List.class) {
|
if (field.getType() == List.class) {
|
||||||
field.setAccessible(true);
|
field.setAccessible(true);
|
||||||
@@ -94,12 +101,10 @@ public final class SpigotInjector extends CommonPlatformInjector {
|
|||||||
|
|
||||||
field.set(serverConnection, newList);
|
field.set(serverConnection, newList);
|
||||||
injected = true;
|
injected = true;
|
||||||
return true;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void injectClient(ChannelFuture future) {
|
public void injectClient(ChannelFuture future) {
|
||||||
future.channel().pipeline().addFirst("floodgate-init", new ChannelInboundHandlerAdapter() {
|
future.channel().pipeline().addFirst("floodgate-init", new ChannelInboundHandlerAdapter() {
|
||||||
@@ -120,36 +125,48 @@ public final class SpigotInjector extends CommonPlatformInjector {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean removeInjection() throws Exception {
|
public void removeInjection() {
|
||||||
if (!isInjected()) {
|
if (!isInjected()) {
|
||||||
return true;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// remove injection from clients
|
// let's change the list back to the original first
|
||||||
for (Channel channel : getInjectedClients()) {
|
// so that new connections are not handled through our custom list
|
||||||
removeAddonsCall(channel);
|
|
||||||
}
|
|
||||||
getInjectedClients().clear();
|
|
||||||
|
|
||||||
// and change the list back to the original
|
|
||||||
Object serverConnection = getServerConnection();
|
Object serverConnection = getServerConnection();
|
||||||
if (serverConnection != null) {
|
if (serverConnection != null) {
|
||||||
Field field = ReflectionUtils.getField(serverConnection.getClass(), injectedFieldName);
|
Field field = ReflectionUtils.getField(serverConnection.getClass(), injectedFieldName);
|
||||||
List<?> list = (List<?>) ReflectionUtils.getValue(serverConnection, field);
|
Object value = ReflectionUtils.getValue(serverConnection, field);
|
||||||
|
|
||||||
if (list instanceof CustomList) {
|
if (value instanceof CustomList) {
|
||||||
CustomList customList = (CustomList) list;
|
// all we have to do is replace the list with the original list.
|
||||||
|
// the original list is up-to-date, so we don't have to clear/add/whatever anything
|
||||||
|
CustomList customList = (CustomList) value;
|
||||||
ReflectionUtils.setValue(serverConnection, field, customList.getOriginalList());
|
ReflectionUtils.setValue(serverConnection, field, customList.getOriginalList());
|
||||||
customList.clear();
|
return;
|
||||||
customList.addAll(list);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// we could replace all references of CustomList that are directly in 'value', but that
|
||||||
|
// only brings you so far. ProtocolLib for example stores the original value
|
||||||
|
// (which would be our CustomList e.g.) in a separate object
|
||||||
|
logger.debug(
|
||||||
|
"Unable to remove all references of Floodgate due to {}! ",
|
||||||
|
value.getClass().getName()
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// remove injection from clients
|
||||||
|
for (Channel channel : injectedClients()) {
|
||||||
|
removeAddonsCall(channel);
|
||||||
|
}
|
||||||
|
|
||||||
|
//todo make sure that all references are removed from the channels,
|
||||||
|
// except from one AttributeKey with Floodgate player data which could be used
|
||||||
|
// after reloading
|
||||||
|
|
||||||
injected = false;
|
injected = false;
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public Object getServerConnection() throws IllegalAccessException, InvocationTargetException {
|
private Object getServerConnection() {
|
||||||
if (serverConnection != null) {
|
if (serverConnection != null) {
|
||||||
return serverConnection;
|
return serverConnection;
|
||||||
}
|
}
|
||||||
@@ -158,14 +175,11 @@ public final class SpigotInjector extends CommonPlatformInjector {
|
|||||||
// method by CraftBukkit to get the instance of the MinecraftServer
|
// method by CraftBukkit to get the instance of the MinecraftServer
|
||||||
Object minecraftServerInstance = ReflectionUtils.invokeStatic(minecraftServer, "getServer");
|
Object minecraftServerInstance = ReflectionUtils.invokeStatic(minecraftServer, "getServer");
|
||||||
|
|
||||||
for (Method method : minecraftServer.getDeclaredMethods()) {
|
Method method = ReflectionUtils.getMethodThatReturns(
|
||||||
if (ClassNames.SERVER_CONNECTION.equals(method.getReturnType())) {
|
minecraftServer, ClassNames.SERVER_CONNECTION, true
|
||||||
// making sure that it's a getter
|
);
|
||||||
if (method.getParameterTypes().length == 0) {
|
|
||||||
serverConnection = method.invoke(minecraftServerInstance);
|
serverConnection = ReflectionUtils.invoke(minecraftServerInstance, method);
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return serverConnection;
|
return serverConnection;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -29,6 +29,8 @@ import com.google.inject.AbstractModule;
|
|||||||
import com.google.inject.Provides;
|
import com.google.inject.Provides;
|
||||||
import com.google.inject.Singleton;
|
import com.google.inject.Singleton;
|
||||||
import com.google.inject.name.Named;
|
import com.google.inject.name.Named;
|
||||||
|
import com.google.inject.name.Names;
|
||||||
|
import java.util.logging.Logger;
|
||||||
import lombok.RequiredArgsConstructor;
|
import lombok.RequiredArgsConstructor;
|
||||||
import org.bukkit.event.Listener;
|
import org.bukkit.event.Listener;
|
||||||
import org.bukkit.plugin.java.JavaPlugin;
|
import org.bukkit.plugin.java.JavaPlugin;
|
||||||
@@ -59,7 +61,12 @@ public final class SpigotPlatformModule extends AbstractModule {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void configure() {
|
protected void configure() {
|
||||||
|
bind(SpigotPlugin.class).toInstance(plugin);
|
||||||
bind(PlatformUtils.class).to(SpigotPlatformUtils.class);
|
bind(PlatformUtils.class).to(SpigotPlatformUtils.class);
|
||||||
|
bind(CommonPlatformInjector.class).to(SpigotInjector.class);
|
||||||
|
bind(Logger.class).annotatedWith(Names.named("logger")).toInstance(plugin.getLogger());
|
||||||
|
bind(FloodgateLogger.class).to(JavaUtilFloodgateLogger.class);
|
||||||
|
bind(SkinApplier.class).to(SpigotSkinApplier.class);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Provides
|
@Provides
|
||||||
@@ -68,12 +75,6 @@ public final class SpigotPlatformModule extends AbstractModule {
|
|||||||
return plugin;
|
return plugin;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Provides
|
|
||||||
@Singleton
|
|
||||||
public FloodgateLogger floodgateLogger(LanguageManager languageManager) {
|
|
||||||
return new JavaUtilFloodgateLogger(plugin.getLogger(), languageManager);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Commands / Listeners
|
Commands / Listeners
|
||||||
*/
|
*/
|
||||||
@@ -98,12 +99,6 @@ public final class SpigotPlatformModule extends AbstractModule {
|
|||||||
DebugAddon / PlatformInjector
|
DebugAddon / PlatformInjector
|
||||||
*/
|
*/
|
||||||
|
|
||||||
@Provides
|
|
||||||
@Singleton
|
|
||||||
public CommonPlatformInjector platformInjector() {
|
|
||||||
return new SpigotInjector();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Provides
|
@Provides
|
||||||
@Named("packetEncoder")
|
@Named("packetEncoder")
|
||||||
public String packetEncoder() {
|
public String packetEncoder() {
|
||||||
@@ -144,12 +139,6 @@ public final class SpigotPlatformModule extends AbstractModule {
|
|||||||
return new SpigotPluginMessageRegistration(plugin);
|
return new SpigotPluginMessageRegistration(plugin);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Provides
|
|
||||||
@Singleton
|
|
||||||
public SkinApplier skinApplier(SpigotVersionSpecificMethods versionSpecificMethods) {
|
|
||||||
return new SpigotSkinApplier(versionSpecificMethods, plugin);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Provides
|
@Provides
|
||||||
@Singleton
|
@Singleton
|
||||||
public SpigotVersionSpecificMethods versionSpecificMethods() {
|
public SpigotVersionSpecificMethods versionSpecificMethods() {
|
||||||
|
|||||||
@@ -25,32 +25,34 @@
|
|||||||
|
|
||||||
package org.geysermc.floodgate.pluginmessage;
|
package org.geysermc.floodgate.pluginmessage;
|
||||||
|
|
||||||
|
import com.google.inject.Inject;
|
||||||
|
import com.google.inject.Singleton;
|
||||||
import com.mojang.authlib.GameProfile;
|
import com.mojang.authlib.GameProfile;
|
||||||
import com.mojang.authlib.properties.Property;
|
import com.mojang.authlib.properties.Property;
|
||||||
import com.mojang.authlib.properties.PropertyMap;
|
import com.mojang.authlib.properties.PropertyMap;
|
||||||
import org.bukkit.Bukkit;
|
import org.bukkit.Bukkit;
|
||||||
import org.bukkit.entity.Player;
|
import org.bukkit.entity.Player;
|
||||||
|
import org.checkerframework.checker.nullness.qual.NonNull;
|
||||||
import org.geysermc.floodgate.SpigotPlugin;
|
import org.geysermc.floodgate.SpigotPlugin;
|
||||||
|
import org.geysermc.floodgate.api.event.skin.SkinApplyEvent;
|
||||||
|
import org.geysermc.floodgate.api.event.skin.SkinApplyEvent.SkinData;
|
||||||
import org.geysermc.floodgate.api.player.FloodgatePlayer;
|
import org.geysermc.floodgate.api.player.FloodgatePlayer;
|
||||||
|
import org.geysermc.floodgate.event.EventBus;
|
||||||
|
import org.geysermc.floodgate.event.skin.SkinApplyEventImpl;
|
||||||
import org.geysermc.floodgate.skin.SkinApplier;
|
import org.geysermc.floodgate.skin.SkinApplier;
|
||||||
import org.geysermc.floodgate.skin.SkinData;
|
import org.geysermc.floodgate.skin.SkinDataImpl;
|
||||||
import org.geysermc.floodgate.util.ClassNames;
|
import org.geysermc.floodgate.util.ClassNames;
|
||||||
import org.geysermc.floodgate.util.ReflectionUtils;
|
import org.geysermc.floodgate.util.ReflectionUtils;
|
||||||
import org.geysermc.floodgate.util.SpigotVersionSpecificMethods;
|
import org.geysermc.floodgate.util.SpigotVersionSpecificMethods;
|
||||||
|
|
||||||
|
@Singleton
|
||||||
public final class SpigotSkinApplier implements SkinApplier {
|
public final class SpigotSkinApplier implements SkinApplier {
|
||||||
private final SpigotVersionSpecificMethods versionSpecificMethods;
|
@Inject private SpigotVersionSpecificMethods versionSpecificMethods;
|
||||||
private final SpigotPlugin plugin;
|
@Inject private SpigotPlugin plugin;
|
||||||
|
@Inject private EventBus eventBus;
|
||||||
public SpigotSkinApplier(
|
|
||||||
SpigotVersionSpecificMethods versionSpecificMethods,
|
|
||||||
SpigotPlugin plugin) {
|
|
||||||
this.versionSpecificMethods = versionSpecificMethods;
|
|
||||||
this.plugin = plugin;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void applySkin(FloodgatePlayer floodgatePlayer, SkinData skinData) {
|
public void applySkin(@NonNull FloodgatePlayer floodgatePlayer, @NonNull SkinData skinData) {
|
||||||
applySkin0(floodgatePlayer, skinData, true);
|
applySkin0(floodgatePlayer, skinData, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -60,9 +62,11 @@ public final class SpigotSkinApplier implements SkinApplier {
|
|||||||
// player is probably not logged in yet
|
// player is probably not logged in yet
|
||||||
if (player == null) {
|
if (player == null) {
|
||||||
if (firstTry) {
|
if (firstTry) {
|
||||||
Bukkit.getScheduler().runTaskLater(plugin,
|
Bukkit.getScheduler().runTaskLater(
|
||||||
|
plugin,
|
||||||
() -> applySkin0(floodgatePlayer, skinData, false),
|
() -> applySkin0(floodgatePlayer, skinData, false),
|
||||||
10 * 1000);
|
10 * 20
|
||||||
|
);
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -73,11 +77,22 @@ public final class SpigotSkinApplier implements SkinApplier {
|
|||||||
throw new IllegalStateException("The GameProfile cannot be null! " + player.getName());
|
throw new IllegalStateException("The GameProfile cannot be null! " + player.getName());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Need to be careful here - getProperties() returns an authlib PropertyMap, which extends
|
||||||
|
// MultiMap from Guava. Floodgate relocates Guava.
|
||||||
PropertyMap properties = profile.getProperties();
|
PropertyMap properties = profile.getProperties();
|
||||||
|
|
||||||
properties.removeAll("textures");
|
SkinData currentSkin = currentSkin(properties);
|
||||||
Property property = new Property("textures", skinData.getValue(), skinData.getSignature());
|
|
||||||
properties.put("textures", property);
|
SkinApplyEvent event = new SkinApplyEventImpl(floodgatePlayer, currentSkin, skinData);
|
||||||
|
event.setCancelled(floodgatePlayer.isLinked());
|
||||||
|
|
||||||
|
eventBus.fire(event);
|
||||||
|
|
||||||
|
if (event.isCancelled()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
replaceSkin(properties, event.newSkin());
|
||||||
|
|
||||||
// By running as a task, we don't run into async issues
|
// By running as a task, we don't run into async issues
|
||||||
plugin.getServer().getScheduler().runTask(plugin, () -> {
|
plugin.getServer().getScheduler().runTask(plugin, () -> {
|
||||||
@@ -89,4 +104,19 @@ public final class SpigotSkinApplier implements SkinApplier {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private SkinData currentSkin(PropertyMap properties) {
|
||||||
|
for (Property texture : properties.get("textures")) {
|
||||||
|
if (!texture.getValue().isEmpty()) {
|
||||||
|
return new SkinDataImpl(texture.getValue(), texture.getSignature());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void replaceSkin(PropertyMap properties, SkinData skinData) {
|
||||||
|
properties.removeAll("textures");
|
||||||
|
Property property = new Property("textures", skinData.value(), skinData.signature());
|
||||||
|
properties.put("textures", property);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
var velocityVersion = "3.0.1"
|
var velocityVersion = "3.1.1"
|
||||||
var log4jVersion = "2.11.2"
|
var log4jVersion = "2.11.2"
|
||||||
var gsonVersion = "2.8.8"
|
var gsonVersion = "2.8.8"
|
||||||
var guavaVersion = "25.1-jre"
|
var guavaVersion = "25.1-jre"
|
||||||
|
|||||||
@@ -29,6 +29,7 @@ import com.google.inject.Inject;
|
|||||||
import com.google.inject.Injector;
|
import com.google.inject.Injector;
|
||||||
import com.velocitypowered.api.event.Subscribe;
|
import com.velocitypowered.api.event.Subscribe;
|
||||||
import com.velocitypowered.api.event.proxy.ProxyInitializeEvent;
|
import com.velocitypowered.api.event.proxy.ProxyInitializeEvent;
|
||||||
|
import com.velocitypowered.api.event.proxy.ProxyShutdownEvent;
|
||||||
import com.velocitypowered.api.plugin.annotation.DataDirectory;
|
import com.velocitypowered.api.plugin.annotation.DataDirectory;
|
||||||
import java.nio.file.Path;
|
import java.nio.file.Path;
|
||||||
import org.geysermc.floodgate.api.logger.FloodgateLogger;
|
import org.geysermc.floodgate.api.logger.FloodgateLogger;
|
||||||
@@ -69,4 +70,9 @@ public final class VelocityPlugin {
|
|||||||
new PluginMessageModule()
|
new PluginMessageModule()
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Subscribe
|
||||||
|
public void onProxyShutdown(ProxyShutdownEvent event) {
|
||||||
|
platform.disable();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -36,21 +36,19 @@ import io.netty.channel.ChannelInitializer;
|
|||||||
import java.lang.reflect.Method;
|
import java.lang.reflect.Method;
|
||||||
import lombok.Getter;
|
import lombok.Getter;
|
||||||
import lombok.RequiredArgsConstructor;
|
import lombok.RequiredArgsConstructor;
|
||||||
import org.geysermc.floodgate.api.logger.FloodgateLogger;
|
|
||||||
import org.geysermc.floodgate.inject.CommonPlatformInjector;
|
import org.geysermc.floodgate.inject.CommonPlatformInjector;
|
||||||
|
|
||||||
@RequiredArgsConstructor
|
@RequiredArgsConstructor
|
||||||
public final class VelocityInjector extends CommonPlatformInjector {
|
public final class VelocityInjector extends CommonPlatformInjector {
|
||||||
private final ProxyServer server;
|
private final ProxyServer server;
|
||||||
private final FloodgateLogger logger;
|
|
||||||
|
|
||||||
@Getter private boolean injected;
|
@Getter private boolean injected;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@SuppressWarnings("rawtypes")
|
@SuppressWarnings("rawtypes")
|
||||||
public boolean inject() {
|
public void inject() {
|
||||||
if (isInjected()) {
|
if (isInjected()) {
|
||||||
return true;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
Object connectionManager = getValue(server, "cm");
|
Object connectionManager = getValue(server, "cm");
|
||||||
@@ -72,7 +70,8 @@ public final class VelocityInjector extends CommonPlatformInjector {
|
|||||||
Method backendSetter = getMethod(backendInitializerHolder, "set", ChannelInitializer.class);
|
Method backendSetter = getMethod(backendInitializerHolder, "set", ChannelInitializer.class);
|
||||||
invoke(backendInitializerHolder, backendSetter,
|
invoke(backendInitializerHolder, backendSetter,
|
||||||
new VelocityChannelInitializer(this, backendInitializer, true));
|
new VelocityChannelInitializer(this, backendInitializer, true));
|
||||||
return injected = true;
|
|
||||||
|
injected = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -81,9 +80,9 @@ public final class VelocityInjector extends CommonPlatformInjector {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean removeInjection() {
|
public void removeInjection() {
|
||||||
logger.error("Floodgate cannot remove itself from Velocity without a reboot");
|
throw new IllegalStateException(
|
||||||
return false;
|
"Floodgate cannot remove itself from Velocity without a reboot");
|
||||||
}
|
}
|
||||||
|
|
||||||
@RequiredArgsConstructor
|
@RequiredArgsConstructor
|
||||||
|
|||||||
@@ -27,17 +27,27 @@ package org.geysermc.floodgate.logger;
|
|||||||
|
|
||||||
import static org.geysermc.floodgate.util.MessageFormatter.format;
|
import static org.geysermc.floodgate.util.MessageFormatter.format;
|
||||||
|
|
||||||
import lombok.RequiredArgsConstructor;
|
import com.google.inject.Inject;
|
||||||
|
import com.google.inject.Singleton;
|
||||||
import org.apache.logging.log4j.Level;
|
import org.apache.logging.log4j.Level;
|
||||||
import org.apache.logging.log4j.core.config.Configurator;
|
import org.apache.logging.log4j.core.config.Configurator;
|
||||||
import org.geysermc.floodgate.api.logger.FloodgateLogger;
|
import org.geysermc.floodgate.api.logger.FloodgateLogger;
|
||||||
|
import org.geysermc.floodgate.config.FloodgateConfig;
|
||||||
import org.geysermc.floodgate.util.LanguageManager;
|
import org.geysermc.floodgate.util.LanguageManager;
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
|
|
||||||
@RequiredArgsConstructor
|
@Singleton
|
||||||
public final class Slf4jFloodgateLogger implements FloodgateLogger {
|
public final class Slf4jFloodgateLogger implements FloodgateLogger {
|
||||||
private final Logger logger;
|
@Inject private Logger logger;
|
||||||
private final LanguageManager languageManager;
|
private LanguageManager languageManager;
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
private void init(LanguageManager languageManager, FloodgateConfig config) {
|
||||||
|
this.languageManager = languageManager;
|
||||||
|
if (config.isDebug() && !logger.isDebugEnabled()) {
|
||||||
|
Configurator.setLevel(logger.getName(), Level.DEBUG);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void error(String message, Object... args) {
|
public void error(String message, Object... args) {
|
||||||
@@ -74,20 +84,6 @@ public final class Slf4jFloodgateLogger implements FloodgateLogger {
|
|||||||
logger.trace(message, args);
|
logger.trace(message, args);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public void enableDebug() {
|
|
||||||
if (!logger.isDebugEnabled()) {
|
|
||||||
Configurator.setLevel(logger.getName(), Level.DEBUG);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void disableDebug() {
|
|
||||||
if (logger.isDebugEnabled()) {
|
|
||||||
Configurator.setLevel(logger.getName(), Level.INFO);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean isDebug() {
|
public boolean isDebug() {
|
||||||
return logger.isDebugEnabled();
|
return logger.isDebugEnabled();
|
||||||
|
|||||||
@@ -56,11 +56,9 @@ import org.geysermc.floodgate.pluginmessage.PluginMessageRegistration;
|
|||||||
import org.geysermc.floodgate.pluginmessage.VelocityPluginMessageRegistration;
|
import org.geysermc.floodgate.pluginmessage.VelocityPluginMessageRegistration;
|
||||||
import org.geysermc.floodgate.pluginmessage.VelocityPluginMessageUtils;
|
import org.geysermc.floodgate.pluginmessage.VelocityPluginMessageUtils;
|
||||||
import org.geysermc.floodgate.skin.SkinApplier;
|
import org.geysermc.floodgate.skin.SkinApplier;
|
||||||
import org.geysermc.floodgate.util.LanguageManager;
|
|
||||||
import org.geysermc.floodgate.util.VelocityCommandUtil;
|
import org.geysermc.floodgate.util.VelocityCommandUtil;
|
||||||
import org.geysermc.floodgate.util.VelocityPlatformUtils;
|
import org.geysermc.floodgate.util.VelocityPlatformUtils;
|
||||||
import org.geysermc.floodgate.util.VelocitySkinApplier;
|
import org.geysermc.floodgate.util.VelocitySkinApplier;
|
||||||
import org.slf4j.Logger;
|
|
||||||
|
|
||||||
@RequiredArgsConstructor
|
@RequiredArgsConstructor
|
||||||
public final class VelocityPlatformModule extends AbstractModule {
|
public final class VelocityPlatformModule extends AbstractModule {
|
||||||
@@ -70,6 +68,8 @@ public final class VelocityPlatformModule extends AbstractModule {
|
|||||||
protected void configure() {
|
protected void configure() {
|
||||||
bind(CommandUtil.class).to(VelocityCommandUtil.class);
|
bind(CommandUtil.class).to(VelocityCommandUtil.class);
|
||||||
bind(PlatformUtils.class).to(VelocityPlatformUtils.class);
|
bind(PlatformUtils.class).to(VelocityPlatformUtils.class);
|
||||||
|
bind(FloodgateLogger.class).to(Slf4jFloodgateLogger.class);
|
||||||
|
bind(SkinApplier.class).to(VelocitySkinApplier.class);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Provides
|
@Provides
|
||||||
@@ -89,12 +89,6 @@ public final class VelocityPlatformModule extends AbstractModule {
|
|||||||
return commandManager;
|
return commandManager;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Provides
|
|
||||||
@Singleton
|
|
||||||
public FloodgateLogger floodgateLogger(Logger logger, LanguageManager languageManager) {
|
|
||||||
return new Slf4jFloodgateLogger(logger, languageManager);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Commands / Listeners
|
Commands / Listeners
|
||||||
*/
|
*/
|
||||||
@@ -119,20 +113,14 @@ public final class VelocityPlatformModule extends AbstractModule {
|
|||||||
return new VelocityPluginMessageRegistration(proxy);
|
return new VelocityPluginMessageRegistration(proxy);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Provides
|
|
||||||
@Singleton
|
|
||||||
public SkinApplier skinApplier(ProxyServer server) {
|
|
||||||
return new VelocitySkinApplier(server);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
DebugAddon / PlatformInjector
|
DebugAddon / PlatformInjector
|
||||||
*/
|
*/
|
||||||
|
|
||||||
@Provides
|
@Provides
|
||||||
@Singleton
|
@Singleton
|
||||||
public CommonPlatformInjector platformInjector(ProxyServer server, FloodgateLogger logger) {
|
public CommonPlatformInjector platformInjector(ProxyServer server) {
|
||||||
return new VelocityInjector(server, logger);
|
return new VelocityInjector(server);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Provides
|
@Provides
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user