Compare commits

..

2 Commits

Author SHA1 Message Date
Camotoy 498b058aba
World border improvements (#488) 2020-06-04 16:56:16 -04:00
Luke 50c4c0b2d8
Initial world border 2020-05-05 14:10:27 +01:00
551 changed files with 13936 additions and 29397 deletions

2
.github/FUNDING.yml vendored
View File

@ -1,7 +1,7 @@
# These are supported funding model platforms
github: # Replace with up to 4 GitHub Sponsors-enabled usernames e.g., [user1, user2]
patreon: #GeyserMC # Disabled currently
patreon: GeyserMC
open_collective: # Replace with a single Open Collective username
ko_fi: # Replace with a single Ko-fi username
tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel

View File

@ -7,51 +7,34 @@ assignees: ''
---
<!--- DELETING THIS TEMPLATE WILL GET YOUR ISSUE CLOSED! --->
<!--- Please follow this format COMPLETELY and make sure the bug you are reporting has not been reported yet. Reports should contain as much information or context as possible to help us find the problem. Simply creating an issue on a vague topic will not help us at all, and if you are unsure if something should belong here, please contact us on [Discord](http://discord.geysermc.org).-->
<!--- Issues pertaining to connection problems, or anything of that covered on the [Common Issues](https://github.com/GeyserMC/Geyser/wiki/Common-Issues) do not belong here and only clutter this issue tracker. -->
<!--- Issues pertaining to connection problem, or anything of that covered on the [Common Issues](https://github.com/GeyserMC/Geyser/wiki/Common-Issues) do not belong here and only clutter this issue tracker. -->
**Describe the bug**
A clear and concise description of what the bug is.
<!--- A clear and concise description of what the bug is. -->
**To Reproduce**
Steps to reproduce the behavior:
1. Go to '...'
2. Click on '....'
3. Scroll down to '....'
4. See error
<!--- Steps to reproduce the behavior: -->
<!--- 1. Go to '...' -->
<!--- 2. Click on '....' -->
<!--- 3. Scroll down to '....' -->
<!--- 4. See error -->
**Expected behavior**
A clear and concise description of what you expected to happen.
<!--- A clear and concise description of what you expected to happen. -->
**Screenshots / Videos**
<!--- If applicable, add screenshots to help explain your problem. -->
If applicable, add screenshots to help explain your problem.
**Server Version**
<!--- Give us the exact output from /version. Saying "latest" does not help us at all. -->
**Server Version and Plugins**
If you just run Geyser-Spigot, you can leave this area blank as the next section covers this information.
If you're running a multi-server instance, or using Geyser Standalone:
- Give us the exact output from `/version` on all servers involved. Saying "latest" does not help us at all.
- Please list all plugins on all servers involved.
If this bug occurs on a server you do not control, please fill this in to the best of your knowledge.
**Geyser Dump**
If Geyser starts correctly, please also include the link to a dump by using `/geyser dump`. If you use the Standalone GUI, the option can be found under `Commands` => `Dump`. This provides us information about your server that we can use to debug your issue.
**Geyser Version**
<!--- Give us the exact build number as well as branch if applicable. Saying "latest" does not help us at all. Please also include if you are running the standalone version, or specify which plugin version you are using. If your issue is a connection problem, please specify if you are using the Floodgate plugin. -->
**Minecraft: Bedrock Edition Version**
The version of your Minecraft: Bedrock Edition client you tested with, along with your device type (e.g. Windows 10, Switch...).
<!-- The version of your Minecraft: Bedrock Edition client you tested with. -->
**Additional Context**
Add any other context about the problem here.
<!--- Add any other context about the problem here. Include any plugins on the Minecraft server that may cause problems. --->

View File

@ -11,4 +11,4 @@ assignees: ''
Add a description
**Alternatives?**
List any alternatives you might have tried
Any alternatives you have tryed

View File

@ -8,8 +8,8 @@ jobs:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- uses: actions/cache@v2
- uses: actions/checkout@v1
- uses: actions/cache@v1
with:
path: ~/.m2/repository
key: ${{ runner.os }}-maven-${{ hashFiles('**/pom.xml') }}
@ -22,33 +22,33 @@ jobs:
- name: submodules-init
uses: snickerbockers/submodules-init@v4
- name: Build with Maven
run: mvn -B package -T 2C
run: mvn -B package
- name: Archive artifacts (Geyser Standalone)
uses: actions/upload-artifact@v2
uses: actions/upload-artifact@v1
if: success()
with:
name: Geyser Standalone
path: bootstrap/standalone/target/Geyser.jar
- name: Archive artifacts (Geyser Spigot)
uses: actions/upload-artifact@v2
- name: Archive artifacts (Geyser Bukkit)
uses: actions/upload-artifact@v1
if: success()
with:
name: Geyser Spigot
path: bootstrap/spigot/target/Geyser-Spigot.jar
name: Geyser Bukkit
path: bootstrap/bukkit/target/Geyser-Bukkit.jar
- name: Archive artifacts (Geyser BungeeCord)
uses: actions/upload-artifact@v2
uses: actions/upload-artifact@v1
if: success()
with:
name: Geyser BungeeCord
path: bootstrap/bungeecord/target/Geyser-BungeeCord.jar
- name: Archive artifacts (Geyser Sponge)
uses: actions/upload-artifact@v2
uses: actions/upload-artifact@v1
if: success()
with:
name: Geyser Sponge
path: bootstrap/sponge/target/Geyser-Sponge.jar
- name: Archive artifacts (Geyser Velocity)
uses: actions/upload-artifact@v2
uses: actions/upload-artifact@v1
if: success()
with:
name: Geyser Velocity

41
.gitignore vendored
View File

@ -1,6 +1,6 @@
# Created by https://www.gitignore.io/api/git,java,maven,eclipse,netbeans,jetbrains+all,visualstudiocode
# Edit at https://www.gitignore.io/gitignore?templates=git,java,maven,eclipse,netbeans,jetbrains+all,visualstudiocode
# Created by https://www.gitignore.io/api/git,java,maven,eclipse,netbeans,jetbrains+all
# Edit at https://www.gitignore.io/?templates=git,java,maven,eclipse,netbeans,jetbrains+all
### Eclipse ###
.metadata
@ -53,19 +53,22 @@ local.properties
# Annotation Processing
.apt_generated/
.apt_generated_test/
# Scala IDE specific (Scala & Java development for Eclipse)
.cache-main
.scala_dependencies
.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:
### Eclipse Patch ###
# Eclipse Core
.project
### Eclipse Patch ###
# Spring Boot Tooling
# JDT-specific (Eclipse Java Development Tools)
.classpath
# Annotation Processing
.apt_generated
.sts4-cache/
### Git ###
@ -109,7 +112,7 @@ local.properties
hs_err_pid*
### JetBrains+all ###
# Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio, WebStorm and Rider
# Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio and WebStorm
# Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839
# User-specific stuff
@ -139,9 +142,6 @@ hs_err_pid*
# 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
# auto-import.
# .idea/artifacts
# .idea/compiler.xml
# .idea/jarRepositories.xml
# .idea/modules.xml
# .idea/*.iml
# .idea/modules
@ -207,7 +207,6 @@ release.properties
dependency-reduced-pom.xml
buildNumber.properties
.mvn/timing.properties
# https://github.com/takari/maven-wrapper#usage-without-binary-jar
.mvn/wrapper/maven-wrapper.jar
### NetBeans ###
@ -220,20 +219,7 @@ dist/
nbdist/
.nb-gradle/
### VisualStudioCode ###
# Note: Manually edited to remove settings files
.vscode/*
# !.vscode/settings.json
# !.vscode/tasks.json
# !.vscode/launch.json
# !.vscode/extensions.json
# *.code-workspace
### VisualStudioCode Patch ###
# Ignore all local history of files
.history
# End of https://www.gitignore.io/api/git,java,maven,eclipse,netbeans,jetbrains+all,visualstudiocode
# End of https://www.gitignore.io/api/git,java,maven,eclipse,netbeans,jetbrains+all
### Geyser ###
run/
@ -241,6 +227,3 @@ config.yml
logs/
public-key.pem
locales/
/cache/
/packs/
/dump.json

3
.gitmodules vendored
View File

@ -1,6 +1,3 @@
[submodule "connector/src/main/resources/mappings"]
path = connector/src/main/resources/mappings
url = https://github.com/GeyserMC/mappings.git
[submodule "connector/src/main/resources/languages"]
path = connector/src/main/resources/languages
url = https://github.com/GeyserMC/languages.git

View File

@ -1,6 +1,6 @@
<component name="CopyrightManager">
<copyright>
<option name="notice" value="Copyright (c) 2019-&amp;#36;today.year GeyserMC. http://geysermc.org&#10;&#10;Permission is hereby granted, free of charge, to any person obtaining a copy&#10;of this software and associated documentation files (the &quot;Software&quot;), to deal&#10;in the Software without restriction, including without limitation the rights&#10;to use, copy, modify, merge, publish, distribute, sublicense, and/or sell&#10;copies of the Software, and to permit persons to whom the Software is&#10;furnished to do so, subject to the following conditions:&#10;&#10;The above copyright notice and this permission notice shall be included in&#10;all copies or substantial portions of the Software.&#10;&#10;THE SOFTWARE IS PROVIDED &quot;AS IS&quot;, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR&#10;IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,&#10;FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE&#10;AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER&#10;LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,&#10;OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN&#10;THE SOFTWARE.&#10;&#10;@author GeyserMC&#10;@link https://github.com/GeyserMC/Geyser" />
<option name="notice" value="Copyright (c) 2019-&amp;#36;today.year GeyserMC. http://geysermc.org&#10; &#10; Permission is hereby granted, free of charge, to any person obtaining a copy&#10; of this software and associated documentation files (the &quot;Software&quot;), to deal&#10; in the Software without restriction, including without limitation the rights&#10; to use, copy, modify, merge, publish, distribute, sublicense, and/or sell&#10; copies of the Software, and to permit persons to whom the Software is&#10; furnished to do so, subject to the following conditions:&#10; &#10; The above copyright notice and this permission notice shall be included in&#10; all copies or substantial portions of the Software.&#10; &#10; THE SOFTWARE IS PROVIDED &quot;AS IS&quot;, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR&#10; IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,&#10; FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE&#10; AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER&#10; LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,&#10; OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN&#10; THE SOFTWARE.&#10; &#10; @author GeyserMC&#10; @link https://github.com/GeyserMC/Geyser&#10; " />
<option name="myName" value="Geyser" />
</copyright>
</component>

View File

@ -1,44 +1 @@
Thank for for considering a contribution! Generally, Geyser welcomes PRs from everyone. There are some guidelines about what features should go where:
*Pull requests that may not get accepted:* Niche features that apply to a specific group, for example integration with a specific plugin. For now, please create a separate plugin if possible.
*Pull requests for Floodgate:* Anything that opens up information within the game for developers to use.
*Pull requests for Geyser:* Anything that fixes compatibility between Java or Bedrock, or improves the quality of play for Bedrock players. The exception is wherever direct server access is required; in this case it may be better for Floodgate.
We have some general style guides that should be applied throughout the code:
```java
private static final AIR_ITEM = 0; // Static item names should be capitalized
public Int2IntMap items = new Int2IntOpenHashMap(); // Use the interface as the class type but initialize with the implementation.
public int nameWithMultipleWords = 0;
/**
* Javadoc comment to explain what a function does.
*/
public void applyStuff() {
if (condition) {
// Do stuff.
} else if (anotherCondition) {
// Do something else.
}
switch (value) {
case 0:
break;
case 1:
break:
}
}
```
Make sure to comment your code where possible.
The nature of our software requires a lot of arrays and maps to be stored - where possible, use Fastutil's specialized maps. For example, if you're storing block state translations, use an `Int2IntMap`.
We have a rundown of all the tools you need to develop over on our [wiki](https://github.com/GeyserMC/Geyser/wiki/Developer-Guide). If you have any questions, please feel free to reach out to our [Discord](https://discord.geysermc.org)!
When contributing, please remember to read wiki about the api. Learn Steivice10's library and the nukkit protocol library if you are editing any core classes. Keep your code clean and readable, and please be mindful of fil conflicts. If you need help, join our discord. Other than that, you're all set!

66
Jenkinsfile vendored
View File

@ -5,7 +5,7 @@ pipeline {
jdk 'Java 8'
}
options {
buildDiscarder(logRotator(artifactNumToKeepStr: '20'))
buildDiscarder(logRotator(artifactNumToKeepStr: '5'))
}
stages {
stage ('Build') {
@ -24,77 +24,17 @@ pipeline {
when {
branch "master"
}
steps {
rtMavenDeployer(
id: "maven-deployer",
serverId: "opencollab-artifactory",
releaseRepo: "maven-releases",
snapshotRepo: "maven-snapshots"
)
rtMavenResolver(
id: "maven-resolver",
serverId: "opencollab-artifactory",
releaseRepo: "release",
snapshotRepo: "snapshot"
)
rtMavenRun(
pom: 'pom.xml',
goals: 'javadoc:jar source:jar install -DskipTests',
deployerId: "maven-deployer",
resolverId: "maven-resolver"
)
rtPublishBuildInfo(
serverId: "opencollab-artifactory"
)
sh 'mvn javadoc:jar source:jar deploy -DskipTests'
}
}
}
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/Geyser)", 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/Geyser-Fabric/java-1.16'
build propagate: false, wait: false, job: 'GeyserMC/GeyserAndroid/master'
}
discordSend description: "**Build:** [${currentBuild.id}](${env.BUILD_URL})\n**Status:** [${currentBuild.currentResult}](${env.BUILD_URL})\n\n[**Artifacts on Jenkins**](https://ci.nukkitx.com/job/Geyser)", footer: 'NukkitX Jenkins', link: env.BUILD_URL, successful: currentBuild.resultIsBetterOrEqualTo('SUCCESS'), title: "${env.JOB_NAME} #${currentBuild.id}", webhookURL: DISCORD_WEBHOOK
}
}
}

View File

@ -1,6 +1,6 @@
The MIT License
Copyright (c) 2019-2021 GeyserMC. http://geysermc.org
Copyright (c) 2019-2020 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

View File

@ -1,12 +1,11 @@
<img src="https://geysermc.org/img/geyser-1760-860.png" alt="Geyser" width="600"/>
<img src="https://geysermc.org/img/geyserlogo.png" alt="Geyser" width="600"/>
[![forthebadge made-with-java](http://ForTheBadge.com/images/badges/made-with-java.svg)](https://java.com/)
[![License: MIT](https://img.shields.io/badge/license-MIT-blue.svg)](LICENSE)
[![Build Status](https://ci.opencollab.dev/job/Geyser/job/master/badge/icon)](https://ci.opencollab.dev/job/GeyserMC/job/Geyser/job/master/)
[![Build Status](https://ci.nukkitx.com/job/Geyser/job/master/badge/icon)](https://ci.nukkitx.com/job/Geyser/job/master/)
[![Discord](https://img.shields.io/discord/613163671870242838.svg?color=%237289da&label=discord)](http://discord.geysermc.org/)
[![HitCount](http://hits.dwyl.io/Geyser/GeyserMC.svg)](http://hits.dwyl.io/Geyser/GeyserMC)
[![Crowdin](https://badges.crowdin.net/geyser/localized.svg)](https://translate.geysermc.org/)
Geyser is a bridge between Minecraft: Bedrock Edition and Minecraft: Java Edition, closing the gap from those wanting to play true cross-platform.
@ -18,7 +17,7 @@ The ultimate goal of this project is to allow Minecraft: Bedrock Edition users t
Special thanks to the DragonProxy project for being a trailblazer in protocol translation and for all the team members who have now joined us here!
### Currently supporting Minecraft Bedrock v1.16.100 - v1.16.201 and Minecraft Java v1.16.4.
### Currently supporting Minecraft Bedrock v1.14.6(0) and Minecraft Java v1.15.2.
## Setting Up
Take a look [here](https://github.com/GeyserMC/Geyser/wiki#Setup) for how to set up Geyser.
@ -30,30 +29,16 @@ Take a look [here](https://github.com/GeyserMC/Geyser/wiki#Setup) for how to set
- Docs: https://github.com/GeyserMC/Geyser/wiki
- Download: http://ci.geysermc.org
- Discord: http://discord.geysermc.org/
- ~~Donate: https://patreon.com/GeyserMC~~ Currently disabled.
- Test Server: `test.geysermc.org` port `25565` for Java and `19132` for Bedrock
- Donate: https://patreon.com/GeyserMC
## What's Left to be Added/Fixed
- Lecterns
- Near-perfect movement (to the point where anticheat on large servers is unlikely to ban you)
- Resource pack conversion/CustomModelData
- Some Entity Flags
- The Following Inventories
- Enchantment Table (as a proper GUI)
- Beacon
- Cartography Table
- Stonecutter
- Structure Block
- Horse Inventory
- Loom
- Smithing Table
## What can't be fixed
The following things can't be fixed because of Bedrock limitations. They might be fixable in the future, but not as of now.
- Custom heads in inventories
- Clickable links in chat
- Glowing effect
- [ ] Enchantment Table
- [ ] Beacon
- [ ] Cartography Table
- [ ] Stonecutter
- [ ] Villager Trading
- Some Entity Flags
## Compiling
1. Clone the repo to your computer

View File

@ -6,37 +6,32 @@
<parent>
<groupId>org.geysermc</groupId>
<artifactId>bootstrap-parent</artifactId>
<version>1.2.0-SNAPSHOT</version>
<version>1.0-SNAPSHOT</version>
<relativePath>../</relativePath>
</parent>
<artifactId>bootstrap-spigot</artifactId>
<artifactId>bootstrap-bukkit</artifactId>
<dependencies>
<dependency>
<groupId>org.geysermc</groupId>
<artifactId>connector</artifactId>
<version>1.2.0-SNAPSHOT</version>
<version>1.0-SNAPSHOT</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>org.spigotmc</groupId>
<artifactId>spigot-api</artifactId>
<version>1.15.2-R0.1-SNAPSHOT</version>
<version>1.14-R0.1-SNAPSHOT</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>us.myles</groupId>
<artifactId>viaversion</artifactId>
<version>3.2.0</version>
<version>3.0.0-SNAPSHOT</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.geysermc.adapters</groupId>
<artifactId>spigot-all</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>
</dependencies>
<build>
<finalName>${outputName}-Spigot</finalName>
<finalName>${outputName}-Bukkit</finalName>
<resources>
<resource>
<directory>src/main/resources/</directory>
@ -51,7 +46,7 @@
<configuration>
<archive>
<manifestEntries>
<Main-Class>org.geysermc.platform.spigot.GeyserSpigotMain</Main-Class>
<Main-Class>org.geysermc.platform.bukkit.GeyserBukkitMain</Main-Class>
</manifestEntries>
</archive>
</configuration>
@ -70,35 +65,11 @@
<relocations>
<relocation>
<pattern>io.netty</pattern>
<shadedPattern>org.geysermc.platform.spigot.shaded.netty</shadedPattern>
<shadedPattern>org.geysermc.platform.bukkit.shaded.netty</shadedPattern>
</relocation>
<relocation>
<pattern>it.unimi.dsi.fastutil</pattern>
<shadedPattern>org.geysermc.platform.spigot.shaded.fastutil</shadedPattern>
</relocation>
<relocation>
<pattern>com.fasterxml.jackson</pattern>
<shadedPattern>org.geysermc.platform.spigot.shaded.jackson</shadedPattern>
</relocation>
<relocation>
<pattern>org.reflections</pattern>
<shadedPattern>org.geysermc.platform.spigot.shaded.reflections</shadedPattern>
</relocation>
<relocation>
<pattern>com.google.common</pattern>
<shadedPattern>org.geysermc.platform.spigot.shaded.google.common</shadedPattern>
</relocation>
<relocation>
<pattern>com.google.guava</pattern>
<shadedPattern>org.geysermc.platform.spigot.shaded.google.guava</shadedPattern>
</relocation>
<relocation>
<pattern>org.dom4j</pattern>
<shadedPattern>org.geysermc.platform.spigot.shaded.dom4j</shadedPattern>
</relocation>
<relocation>
<pattern>net.kyori</pattern>
<shadedPattern>org.geysermc.platform.spigot.shaded.kyori</shadedPattern>
<shadedPattern>org.geysermc.platform.bukkit.shaded.fastutil</shadedPattern>
</relocation>
</relocations>
</configuration>

View File

@ -0,0 +1,241 @@
/*
* Copyright (c) 2019-2020 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/Geyser
*/
package org.geysermc.platform.bukkit;
import org.bukkit.Bukkit;
import org.bukkit.configuration.file.FileConfiguration;
import org.bukkit.plugin.Plugin;
import org.geysermc.connector.FloodgateKeyLoader;
import org.geysermc.connector.GeyserConfiguration;
import java.io.File;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.HashMap;
import java.util.Map;
public class GeyserBukkitConfiguration implements GeyserConfiguration {
private FileConfiguration config;
private File dataFolder;
private BukkitBedrockConfiguration bedrockConfig;
private BukkitRemoteConfiguration remoteConfig;
private BukkitMetricsInfo metricsInfo;
private Map<String, BukkitUserAuthenticationInfo> userAuthInfo = new HashMap<>();
private Path floodgateKey;
public GeyserBukkitConfiguration(File dataFolder, FileConfiguration config) {
this.dataFolder = dataFolder;
this.config = config;
bedrockConfig = new BukkitBedrockConfiguration();
remoteConfig = new BukkitRemoteConfiguration();
metricsInfo = new BukkitMetricsInfo();
if (!config.contains("userAuths"))
return;
for (String key : config.getConfigurationSection("userAuths").getKeys(false)) {
userAuthInfo.put(key, new BukkitUserAuthenticationInfo(key));
}
}
public void loadFloodgate(GeyserBukkitPlugin plugin) {
Plugin floodgate = Bukkit.getPluginManager().getPlugin("floodgate-bukkit");
floodgateKey = FloodgateKeyLoader.getKey(plugin.getGeyserLogger(), this, Paths.get(dataFolder.toString(), config.getString("floodgate-key-file", "public-key.pem")), floodgate, floodgate != null ? floodgate.getDataFolder().toPath() : null);
}
@Override
public IBedrockConfiguration getBedrock() {
return bedrockConfig;
}
@Override
public IRemoteConfiguration getRemote() {
return remoteConfig;
}
@Override
public Map<String, BukkitUserAuthenticationInfo> getUserAuths() {
return userAuthInfo;
}
@Override
public boolean isCommandSuggestions() {
return config.getBoolean("command-suggestions", true);
}
@Override
public boolean isPassthroughMotd() {
return config.getBoolean("passthrough-motd", false);
}
@Override
public boolean isPassthroughPlayerCounts() {
return config.getBoolean("passthrough-player-counts", false);
}
@Override
public boolean isLegacyPingPassthrough() {
return config.getBoolean("legacy-ping-passthrough", false);
}
@Override
public int getPingPassthroughInterval() {
return config.getInt("ping-passthrough-interval", 3);
}
@Override
public int getMaxPlayers() {
return config.getInt("max-players", 10);
}
@Override
public boolean isDebugMode() {
return config.getBoolean("debug-mode", false);
}
@Override
public int getGeneralThreadPool() {
return config.getInt("general-thread-pool", 32);
}
@Override
public boolean isAllowThirdPartyCapes() {
return config.getBoolean("allow-third-party-capes", true);
}
@Override
public boolean isAllowThirdPartyEars() {
return config.getBoolean("allow-third-party-ears", false);
}
@Override
public String getDefaultLocale() {
return config.getString("default-locale", "en_us");
}
@Override
public Path getFloodgateKeyFile() {
return floodgateKey;
}
@Override
public boolean isCacheChunks() {
return true; // We override this as with Bukkit, we have direct access to the server implementation
}
@Override
public boolean isAboveBedrockNetherBuilding() {
return config.getBoolean("above-bedrock-nether-building", false);
}
@Override
public IMetricsInfo getMetrics() {
return metricsInfo;
}
public class BukkitBedrockConfiguration implements IBedrockConfiguration {
@Override
public String getAddress() {
return config.getString("bedrock.address", "0.0.0.0");
}
@Override
public int getPort() {
return config.getInt("bedrock.port", 25565);
}
@Override
public String getMotd1() {
return config.getString("bedrock.motd1", "GeyserMC");
}
@Override
public String getMotd2() {
return config.getString("bedrock.motd2", "GeyserMC");
}
}
public class BukkitRemoteConfiguration implements IRemoteConfiguration {
@Override
public String getAddress() {
return config.getString("remote.address", "127.0.0.1");
}
@Override
public int getPort() {
return config.getInt("remote.port", 25565);
}
@Override
public String getAuthType() {
return config.getString("remote.auth-type", "online");
}
}
public class BukkitUserAuthenticationInfo implements IUserAuthenticationInfo {
private String key;
public BukkitUserAuthenticationInfo(String key) {
this.key = key;
}
@Override
public String getEmail() {
return config.getString("userAuths." + key + ".email");
}
@Override
public String getPassword() {
return config.getString("userAuths." + key + ".password");
}
}
public class BukkitMetricsInfo implements IMetricsInfo {
@Override
public boolean isEnabled() {
return config.getBoolean("metrics.enabled", true);
}
@Override
public String getUniqueId() {
return config.getString("metrics.uuid", "generateduuid");
}
}
@Override
public int getConfigVersion() {
return config.getInt("config-version", 0);
}
}

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2019-2021 GeyserMC. http://geysermc.org
* Copyright (c) 2019-2020 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
@ -23,21 +23,20 @@
* @link https://github.com/GeyserMC/Geyser
*/
package org.geysermc.platform.spigot;
package org.geysermc.platform.bukkit;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.Setter;
import org.geysermc.connector.GeyserLogger;
import java.util.logging.Level;
import java.util.logging.Logger;
@AllArgsConstructor
public class GeyserSpigotLogger implements GeyserLogger {
private final Logger logger;
@Getter @Setter
private boolean debug;
public class GeyserBukkitLogger implements GeyserLogger {
private Logger logger;
private boolean debugMode;
@Override
public void severe(String message) {
@ -71,8 +70,12 @@ public class GeyserSpigotLogger implements GeyserLogger {
@Override
public void debug(String message) {
if (debug) {
if (debugMode)
info(message);
}
}
@Override
public void setDebug(boolean debug) {
debugMode = debug;
}
}

View File

@ -0,0 +1,44 @@
/*
* Copyright (c) 2019-2020 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/Geyser
*
*/
package org.geysermc.platform.bukkit;
import org.geysermc.common.main.IGeyserMain;
public class GeyserBukkitMain extends IGeyserMain {
public static void main(String[] args) {
new GeyserBukkitMain().displayMessage();
}
public String getPluginType() {
return "Spigot or Paper (recommended)";
}
public String getPluginFolder() {
return "plugins";
}
}

View File

@ -0,0 +1,79 @@
/*
* Copyright (c) 2019-2020 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/Geyser
*
*/
package org.geysermc.platform.bukkit;
import lombok.AllArgsConstructor;
import org.bukkit.Bukkit;
import org.bukkit.entity.Player;
import org.bukkit.event.server.ServerListPingEvent;
import org.bukkit.util.CachedServerIcon;
import org.geysermc.common.ping.GeyserPingInfo;
import org.geysermc.connector.ping.IGeyserPingPassthrough;
import java.net.InetAddress;
import java.util.Collections;
import java.util.Iterator;
@AllArgsConstructor
public class GeyserBukkitPingPassthrough implements IGeyserPingPassthrough {
private final GeyserBukkitLogger logger;
@Override
public GeyserPingInfo getPingInformation() {
try {
ServerListPingEvent event = new GeyserPingEvent(InetAddress.getLocalHost(), Bukkit.getMotd(), Bukkit.getOnlinePlayers().size(), Bukkit.getMaxPlayers());
Bukkit.getPluginManager().callEvent(event);
GeyserPingInfo geyserPingInfo = new GeyserPingInfo(event.getMotd(), event.getNumPlayers(), event.getMaxPlayers());
Bukkit.getOnlinePlayers().forEach(player -> {
geyserPingInfo.addPlayer(player.getName());
});
return geyserPingInfo;
} catch (Exception e) {
logger.debug("Error while getting Bukkit ping passthrough: " + e.toString());
return new GeyserPingInfo(null, 0, 0);
}
}
// These methods are unimplemented on spigot api by default so we add stubs so plugins don't complain
private static class GeyserPingEvent extends ServerListPingEvent {
public GeyserPingEvent(InetAddress address, String motd, int numPlayers, int maxPlayers) {
super(address, motd, numPlayers, maxPlayers);
}
@Override
public void setServerIcon(CachedServerIcon icon) throws IllegalArgumentException, UnsupportedOperationException {
}
@Override
public Iterator<Player> iterator() throws UnsupportedOperationException {
return Collections.EMPTY_LIST.iterator();
}
}
}

View File

@ -0,0 +1,177 @@
/*
* Copyright (c) 2019-2020 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/Geyser
*/
package org.geysermc.platform.bukkit;
import org.bukkit.Bukkit;
import org.bukkit.plugin.java.JavaPlugin;
import org.geysermc.common.PlatformType;
import org.geysermc.connector.GeyserConfiguration;
import org.geysermc.connector.GeyserConnector;
import org.geysermc.connector.bootstrap.GeyserBootstrap;
import org.geysermc.connector.command.CommandManager;
import org.geysermc.connector.network.translators.world.WorldManager;
import org.geysermc.connector.ping.GeyserLegacyPingPassthrough;
import org.geysermc.connector.ping.IGeyserPingPassthrough;
import org.geysermc.platform.bukkit.command.GeyserBukkitCommandExecutor;
import org.geysermc.platform.bukkit.command.GeyserBukkitCommandManager;
import org.geysermc.platform.bukkit.world.GeyserBukkitBlockPlaceListener;
import org.geysermc.platform.bukkit.world.GeyserBukkitWorldManager;
import us.myles.ViaVersion.api.Via;
import java.util.UUID;
public class GeyserBukkitPlugin extends JavaPlugin implements GeyserBootstrap {
private GeyserBukkitCommandManager geyserCommandManager;
private GeyserBukkitConfiguration geyserConfig;
private GeyserBukkitLogger geyserLogger;
private IGeyserPingPassthrough geyserBukkitPingPassthrough;
private GeyserBukkitBlockPlaceListener blockPlaceListener;
private GeyserBukkitWorldManager geyserWorldManager;
private GeyserConnector connector;
@Override
public void onEnable() {
saveDefaultConfig();
this.geyserConfig = new GeyserBukkitConfiguration(getDataFolder(), getConfig());
if (geyserConfig.getMetrics().getUniqueId().equals("generateduuid")) {
getConfig().set("metrics.uuid", UUID.randomUUID().toString());
saveConfig();
}
// Don't change the ip if its listening on all interfaces
// By default this should be 127.0.0.1 but may need to be changed in some circumstances
if (!Bukkit.getIp().equals("0.0.0.0") && !Bukkit.getIp().equals("")) {
getConfig().set("remote.address", Bukkit.getIp());
}
getConfig().set("remote.port", Bukkit.getPort());
saveConfig();
this.geyserLogger = new GeyserBukkitLogger(getLogger(), geyserConfig.isDebugMode());
GeyserConfiguration.checkGeyserConfiguration(geyserConfig, geyserLogger);
geyserConfig.loadFloodgate(this);
this.connector = GeyserConnector.start(PlatformType.BUKKIT, this);
if (geyserConfig.isLegacyPingPassthrough()) {
this.geyserBukkitPingPassthrough = GeyserLegacyPingPassthrough.init(connector);
} else {
this.geyserBukkitPingPassthrough = new GeyserBukkitPingPassthrough(geyserLogger);
}
this.geyserCommandManager = new GeyserBukkitCommandManager(this, connector);
boolean isViaVersion = false;
// Used to determine if Block.getBlockData() is present.
boolean isLegacy = !isCompatible(Bukkit.getServer().getVersion(), "1.13.0");
if (isLegacy)
geyserLogger.debug("Legacy version of Minecraft (1.12.2 or older) detected.");
if (Bukkit.getPluginManager().getPlugin("ViaVersion") != null) {
// TODO: Update when ViaVersion updates
// API changes between 2.2.3 and 3.0.0-SNAPSHOT require this check
if (!Via.getAPI().getVersion().equals("3.0.0-SNAPSHOT") && isLegacy) {
geyserLogger.info("ViaVersion detected but not ViaVersion-ABSTRACTION. Please update your ViaVersion plugin for compatibility with Geyser.");
} else {
isViaVersion = true;
}
}
this.geyserWorldManager = new GeyserBukkitWorldManager(isLegacy, isViaVersion);
this.blockPlaceListener = new GeyserBukkitBlockPlaceListener(connector, isLegacy, isViaVersion);
Bukkit.getServer().getPluginManager().registerEvents(blockPlaceListener, this);
this.getCommand("geyser").setExecutor(new GeyserBukkitCommandExecutor(connector));
}
@Override
public void onDisable() {
connector.shutdown();
}
@Override
public GeyserBukkitConfiguration getGeyserConfig() {
return geyserConfig;
}
@Override
public GeyserBukkitLogger getGeyserLogger() {
return geyserLogger;
}
@Override
public CommandManager getGeyserCommandManager() {
return this.geyserCommandManager;
}
@Override
public IGeyserPingPassthrough getGeyserPingPassthrough() {
return geyserBukkitPingPassthrough;
}
@Override
public WorldManager getWorldManager() {
return this.geyserWorldManager;
}
public boolean isCompatible(String version, String whichVersion) {
int[] currentVersion = parseVersion(version);
int[] otherVersion = parseVersion(whichVersion);
int length = Math.max(currentVersion.length, otherVersion.length);
for (int index = 0; index < length; index = index + 1) {
int self = (index < currentVersion.length) ? currentVersion[index] : 0;
int other = (index < otherVersion.length) ? otherVersion[index] : 0;
if (self != other) {
return (self - other) > 0;
}
}
return true;
}
private int[] parseVersion(String versionParam) {
versionParam = (versionParam == null) ? "" : versionParam;
if (versionParam.contains("(MC: ")) {
versionParam = versionParam.split("\\(MC: ")[1];
versionParam = versionParam.split("\\)")[0];
}
String[] stringArray = versionParam.split("[_.-]");
int[] temp = new int[stringArray.length];
for (int index = 0; index <= (stringArray.length - 1); index = index + 1) {
String t = stringArray[index].replaceAll("\\D", "");
try {
temp[index] = Integer.parseInt(t);
} catch(NumberFormatException ex) {
temp[index] = 0;
}
}
return temp;
}
}

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2019-2021 GeyserMC. http://geysermc.org
* Copyright (c) 2019-2020 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
@ -23,21 +23,30 @@
* @link https://github.com/GeyserMC/Geyser
*/
package org.geysermc.platform.spigot;
package org.geysermc.platform.bukkit.command;
import org.geysermc.connector.common.main.IGeyserMain;
import lombok.AllArgsConstructor;
public class GeyserSpigotMain extends IGeyserMain {
import org.bukkit.command.ConsoleCommandSender;
import org.geysermc.connector.command.CommandSender;
public static void main(String[] args) {
new GeyserSpigotMain().displayMessage();
@AllArgsConstructor
public class BukkitCommandSender implements CommandSender {
private org.bukkit.command.CommandSender handle;
@Override
public String getName() {
return handle.getName();
}
public String getPluginType() {
return "Spigot or Paper (recommended)";
@Override
public void sendMessage(String message) {
handle.sendMessage(message);
}
public String getPluginFolder() {
return "plugins";
@Override
public boolean isConsole() {
return handle instanceof ConsoleCommandSender;
}
}

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2019-2021 GeyserMC. http://geysermc.org
* Copyright (c) 2019-2020 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
@ -23,42 +23,39 @@
* @link https://github.com/GeyserMC/Geyser
*/
package org.geysermc.platform.spigot.command;
package org.geysermc.platform.bukkit.command;
import lombok.AllArgsConstructor;
import org.bukkit.ChatColor;
import org.bukkit.command.Command;
import org.bukkit.command.CommandSender;
import org.bukkit.command.TabExecutor;
import org.geysermc.connector.GeyserConnector;
import org.geysermc.connector.command.GeyserCommand;
import org.geysermc.connector.utils.LanguageUtils;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
@AllArgsConstructor
public class GeyserSpigotCommandExecutor implements TabExecutor {
public class GeyserBukkitCommandExecutor implements TabExecutor {
private final GeyserConnector connector;
private GeyserConnector connector;
@Override
public boolean onCommand(CommandSender sender, Command command, String label, String[] args) {
if (args.length > 0) {
if (getCommand(args[0]) != null) {
if (!sender.hasPermission(getCommand(args[0]).getPermission())) {
SpigotCommandSender commandSender = new SpigotCommandSender(sender);
String message = LanguageUtils.getPlayerLocaleString("geyser.bootstrap.command.permission_fail", commandSender.getLocale());;
commandSender.sendMessage(ChatColor.RED + message);
sender.sendMessage(ChatColor.RED + "You do not have permission to execute this command!");
return true;
}
getCommand(args[0]).execute(new SpigotCommandSender(sender), args.length > 1 ? Arrays.copyOfRange(args, 1, args.length) : new String[0]);
getCommand(args[0]).execute(new BukkitCommandSender(sender), args);
return true;
}
} else {
getCommand("help").execute(new SpigotCommandSender(sender), new String[0]);
getCommand("help").execute(new BukkitCommandSender(sender), args);
return true;
}
return true;
@ -67,7 +64,7 @@ public class GeyserSpigotCommandExecutor implements TabExecutor {
@Override
public List<String> onTabComplete(CommandSender sender, Command command, String label, String[] args) {
if (args.length == 1) {
return connector.getCommandManager().getCommandNames();
return Arrays.asList("?", "help", "reload", "shutdown", "stop");
}
return new ArrayList<>();
}

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2019-2021 GeyserMC. http://geysermc.org
* Copyright (c) 2019-2020 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
@ -23,18 +23,18 @@
* @link https://github.com/GeyserMC/Geyser
*/
package org.geysermc.platform.spigot.command;
package org.geysermc.platform.bukkit.command;
import org.bukkit.Bukkit;
import org.bukkit.command.Command;
import org.bukkit.command.CommandMap;
import org.geysermc.connector.GeyserConnector;
import org.geysermc.connector.command.CommandManager;
import org.geysermc.platform.spigot.GeyserSpigotPlugin;
import org.geysermc.platform.bukkit.GeyserBukkitPlugin;
import java.lang.reflect.Field;
public class GeyserSpigotCommandManager extends CommandManager {
public class GeyserBukkitCommandManager extends CommandManager {
private static CommandMap COMMAND_MAP;
@ -48,9 +48,9 @@ public class GeyserSpigotCommandManager extends CommandManager {
}
}
private GeyserSpigotPlugin plugin;
private GeyserBukkitPlugin plugin;
public GeyserSpigotCommandManager(GeyserSpigotPlugin plugin, GeyserConnector connector) {
public GeyserBukkitCommandManager(GeyserBukkitPlugin plugin, GeyserConnector connector) {
super(connector);
this.plugin = plugin;

View File

@ -0,0 +1,73 @@
/*
* Copyright (c) 2019-2020 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/Geyser
*
*/
package org.geysermc.platform.bukkit.world;
import com.nukkitx.math.vector.Vector3f;
import com.nukkitx.protocol.bedrock.data.SoundEvent;
import com.nukkitx.protocol.bedrock.packet.LevelSoundEventPacket;
import lombok.AllArgsConstructor;
import org.bukkit.Bukkit;
import org.bukkit.event.EventHandler;
import org.bukkit.event.Listener;
import org.bukkit.event.block.BlockPlaceEvent;
import org.geysermc.connector.GeyserConnector;
import org.geysermc.connector.network.session.GeyserSession;
import org.geysermc.connector.network.translators.world.block.BlockTranslator;
@AllArgsConstructor
public class GeyserBukkitBlockPlaceListener implements Listener {
private final GeyserConnector connector;
private final boolean isLegacy;
private final boolean isViaVersion;
@EventHandler
public void place(final BlockPlaceEvent event) {
for (GeyserSession session : connector.getPlayers().values()) {
if (event.getPlayer() == Bukkit.getPlayer(session.getPlayerEntity().getUsername())) {
LevelSoundEventPacket placeBlockSoundPacket = new LevelSoundEventPacket();
placeBlockSoundPacket.setSound(SoundEvent.PLACE);
placeBlockSoundPacket.setPosition(Vector3f.from(event.getBlockPlaced().getX(), event.getBlockPlaced().getY(), event.getBlockPlaced().getZ()));
placeBlockSoundPacket.setBabySound(false);
String javaBlockId;
if (isLegacy) {
javaBlockId = BlockTranslator.getJavaIdBlockMap().inverse().get(GeyserBukkitWorldManager.getLegacyBlock(session,
event.getBlockPlaced().getX(), event.getBlockPlaced().getY(), event.getBlockPlaced().getZ(), isViaVersion));
} else {
javaBlockId = event.getBlockPlaced().getBlockData().getAsString();
}
placeBlockSoundPacket.setExtraData(BlockTranslator.getBedrockBlockId(BlockTranslator.getJavaIdBlockMap().get(javaBlockId)));
placeBlockSoundPacket.setIdentifier(":");
session.sendUpstreamPacket(placeBlockSoundPacket);
session.setLastBlockPlacePosition(null);
session.setLastBlockPlacedId(null);
break;
}
}
}
}

View File

@ -0,0 +1,76 @@
/*
* Copyright (c) 2019-2020 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/Geyser
*
*/
package org.geysermc.platform.bukkit.world;
import com.github.steveice10.mc.protocol.data.game.world.block.BlockState;
import lombok.AllArgsConstructor;
import lombok.Getter;
import org.bukkit.Bukkit;
import org.bukkit.block.Block;
import org.geysermc.connector.network.session.GeyserSession;
import org.geysermc.connector.network.translators.world.WorldManager;
import org.geysermc.connector.network.translators.world.block.BlockTranslator;
import org.geysermc.platform.bukkit.GeyserBukkitPlugin;
import us.myles.ViaVersion.protocols.protocol1_13_1to1_13.Protocol1_13_1To1_13;
import us.myles.ViaVersion.protocols.protocol1_15to1_14_4.data.MappingData;
@AllArgsConstructor
public class GeyserBukkitWorldManager extends WorldManager {
private final boolean isLegacy;
// You need ViaVersion to connect to an older server with Geyser.
// However, we still check for ViaVersion in case there's some other way that gets Geyser on a pre-1.13 Bukkit server
private final boolean isViaVersion;
@Override
public BlockState getBlockAt(GeyserSession session, int x, int y, int z) {
if (session.getPlayerEntity() == null) {
return BlockTranslator.AIR;
}
if (isLegacy) {
return getLegacyBlock(session, x, y, z, isViaVersion);
}
return BlockTranslator.getJavaIdBlockMap().get(Bukkit.getPlayer(session.getPlayerEntity().getUsername()).getWorld().getBlockAt(x, y, z).getBlockData().getAsString());
}
@SuppressWarnings("deprecation")
public static BlockState getLegacyBlock(GeyserSession session, int x, int y, int z, boolean isViaVersion) {
if (isViaVersion) {
Block block = Bukkit.getPlayer(session.getPlayerEntity().getUsername()).getWorld().getBlockAt(x, y, z);
// Black magic that gets the old block state ID
int oldBlockId = (block.getType().getId() << 4) | (block.getData() & 0xF);
// Convert block state from old version -> 1.13 -> 1.13.1 -> 1.14 -> 1.15
int thirteenBlockId = us.myles.ViaVersion.protocols.protocol1_13to1_12_2.data.MappingData.blockMappings.getNewId(oldBlockId);
int thirteenPointOneBlockId = Protocol1_13_1To1_13.getNewBlockStateId(thirteenBlockId);
int fourteenBlockId = us.myles.ViaVersion.protocols.protocol1_14to1_13_2.data.MappingData.blockStateMappings.getNewId(thirteenPointOneBlockId);
return new BlockState(MappingData.blockStateMappings.getNewId(fourteenBlockId));
} else {
return BlockTranslator.AIR;
}
}
}

View File

@ -1,5 +1,5 @@
main: org.geysermc.platform.spigot.GeyserSpigotPlugin
name: ${outputName}-Spigot
main: org.geysermc.platform.bukkit.GeyserBukkitPlugin
name: ${outputName}-Bukkit
author: ${project.organization.name}
website: ${project.organization.url}
version: ${project.version}

View File

@ -6,15 +6,15 @@
<parent>
<groupId>org.geysermc</groupId>
<artifactId>bootstrap-parent</artifactId>
<version>1.2.0-SNAPSHOT</version>
<version>1.0-SNAPSHOT</version>
<relativePath>../</relativePath>
</parent>
<artifactId>bootstrap-bungeecord</artifactId>
<dependencies>
<dependency>
<groupId>org.geysermc</groupId>
<artifactId>connector</artifactId>
<version>1.2.0-SNAPSHOT</version>
<version>1.0-SNAPSHOT</version>
<scope>compile</scope>
</dependency>
<dependency>
@ -61,34 +61,10 @@
<pattern>net.md_5.bungee.jni</pattern>
<shadedPattern>org.geysermc.platform.bungeecord.shaded.jni</shadedPattern>
</relocation>
<relocation>
<pattern>com.fasterxml.jackson</pattern>
<shadedPattern>org.geysermc.platform.bungeecord.shaded.jackson</shadedPattern>
</relocation>
<relocation>
<pattern>io.netty</pattern>
<shadedPattern>org.geysermc.platform.bungeecord.shaded.netty</shadedPattern>
</relocation>
<relocation>
<pattern>org.reflections</pattern>
<shadedPattern>org.geysermc.platform.bungeecord.shaded.reflections</shadedPattern>
</relocation>
<relocation>
<pattern>com.google.common</pattern>
<shadedPattern>org.geysermc.platform.bungeecord.shaded.google.common</shadedPattern>
</relocation>
<relocation>
<pattern>com.google.guava</pattern>
<shadedPattern>org.geysermc.platform.bungeecord.shaded.google.guava</shadedPattern>
</relocation>
<relocation>
<pattern>org.dom4j</pattern>
<shadedPattern>org.geysermc.platform.bungeecord.shaded.dom4j</shadedPattern>
</relocation>
<relocation>
<pattern>net.kyori</pattern>
<shadedPattern>org.geysermc.platform.bungeecord.shaded.kyori</shadedPattern>
</relocation>
</relocations>
</configuration>
</execution>

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2019-2021 GeyserMC. http://geysermc.org
* Copyright (c) 2019-2020 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
@ -25,26 +25,216 @@
package org.geysermc.platform.bungeecord;
import com.fasterxml.jackson.annotation.JsonIgnore;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import lombok.Getter;
import net.md_5.bungee.api.plugin.Plugin;
import net.md_5.bungee.config.Configuration;
import org.geysermc.connector.FloodgateKeyLoader;
import org.geysermc.connector.configuration.GeyserJacksonConfiguration;
import org.geysermc.connector.GeyserConfiguration;
import java.io.File;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.HashMap;
import java.util.Map;
@Getter
@JsonIgnoreProperties(ignoreUnknown = true)
public final class GeyserBungeeConfiguration extends GeyserJacksonConfiguration {
@JsonIgnore
private Path floodgateKeyPath;
public class GeyserBungeeConfiguration implements GeyserConfiguration {
private File dataFolder;
private Configuration config;
private BungeeBedrockConfiguration bedrockConfig;
private BungeeRemoteConfiguration remoteConfig;
private BungeeMetricsInfo metricsInfo;
private Map<String, BungeeUserAuthenticationInfo> userAuthInfo = new HashMap<>();
private Path floodgateKey;
public GeyserBungeeConfiguration(File dataFolder, Configuration config) {
this.dataFolder = dataFolder;
this.config = config;
bedrockConfig = new BungeeBedrockConfiguration();
remoteConfig = new BungeeRemoteConfiguration();
metricsInfo = new BungeeMetricsInfo();
if (!config.contains("userAuths"))
return;
for (String key : config.getSection("userAuths").getKeys()) {
userAuthInfo.put(key, new BungeeUserAuthenticationInfo(key));
}
}
public void loadFloodgate(GeyserBungeePlugin plugin) {
Plugin floodgate = plugin.getProxy().getPluginManager().getPlugin("floodgate-bungee");
Path geyserDataFolder = plugin.getDataFolder().toPath();
Path floodgateDataFolder = floodgate != null ? floodgate.getDataFolder().toPath() : null;
floodgateKey = FloodgateKeyLoader.getKey(plugin.getGeyserLogger(), this, Paths.get(dataFolder.toString(), config.getString("floodgate-key-file", "public-key.pem")), floodgate, floodgate != null ? floodgate.getDataFolder().toPath() : null);
}
floodgateKeyPath = FloodgateKeyLoader.getKeyPath(this, floodgate, floodgateDataFolder, geyserDataFolder, plugin.getGeyserLogger());
@Override
public BungeeBedrockConfiguration getBedrock() {
return bedrockConfig;
}
@Override
public BungeeRemoteConfiguration getRemote() {
return remoteConfig;
}
@Override
public Map<String, BungeeUserAuthenticationInfo> getUserAuths() {
return userAuthInfo;
}
@Override
public boolean isCommandSuggestions() {
return config.getBoolean("command-suggestions", true);
}
@Override
public boolean isPassthroughMotd() {
return config.getBoolean("passthrough-motd", false);
}
@Override
public boolean isPassthroughPlayerCounts() {
return config.getBoolean("passthrough-player-counts", false);
}
@Override
public boolean isLegacyPingPassthrough() {
return config.getBoolean("legacy-ping-passthrough", false);
}
@Override
public int getPingPassthroughInterval() {
return config.getInt("ping-passthrough-interval", 3);
}
@Override
public int getMaxPlayers() {
return config.getInt("max-players", 10);
}
@Override
public boolean isDebugMode() {
return config.getBoolean("debug-mode", false);
}
@Override
public int getGeneralThreadPool() {
return config.getInt("general-thread-pool", 32);
}
@Override
public boolean isAllowThirdPartyCapes() {
return config.getBoolean("allow-third-party-capes", true);
}
@Override
public boolean isAllowThirdPartyEars() {
return config.getBoolean("allow-third-party-ears", false);
}
@Override
public String getDefaultLocale() {
return config.getString("default-locale", "en_us");
}
@Override
public Path getFloodgateKeyFile() {
return floodgateKey;
}
@Override
public boolean isCacheChunks() {
return config.getBoolean("cache-chunks", false);
}
@Override
public boolean isAboveBedrockNetherBuilding() {
return config.getBoolean("above-bedrock-nether-building", false);
}
@Override
public BungeeMetricsInfo getMetrics() {
return metricsInfo;
}
public class BungeeBedrockConfiguration implements IBedrockConfiguration {
@Override
public String getAddress() {
return config.getString("bedrock.address", "0.0.0.0");
}
@Override
public int getPort() {
return config.getInt("bedrock.port", 25565);
}
@Override
public String getMotd1() {
return config.getString("bedrock.motd1", "GeyserMC");
}
@Override
public String getMotd2() {
return config.getString("bedrock.motd2", "GeyserMC");
}
}
public class BungeeRemoteConfiguration implements IRemoteConfiguration {
@Override
public String getAddress() {
return config.getString("remote.address", "127.0.0.1");
}
@Override
public int getPort() {
return config.getInt("remote.port", 25565);
}
@Override
public String getAuthType() {
return config.getString("remote.auth-type", "online");
}
}
public class BungeeUserAuthenticationInfo implements IUserAuthenticationInfo {
private String key;
public BungeeUserAuthenticationInfo(String key) {
this.key = key;
}
@Override
public String getEmail() {
return config.getString("userAuths." + key + ".email");
}
@Override
public String getPassword() {
return config.getString("userAuths." + key + ".password");
}
}
public class BungeeMetricsInfo implements IMetricsInfo {
@Override
public boolean isEnabled() {
return config.getBoolean("metrics.enabled", true);
}
@Override
public String getUniqueId() {
return config.getString("metrics.uuid", "generateduuid");
}
}
@Override
public int getConfigVersion() {
return config.getInt("config-version", 0);
}
}

View File

@ -1,69 +0,0 @@
/*
* Copyright (c) 2019-2021 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/Geyser
*/
package org.geysermc.platform.bungeecord;
import lombok.Getter;
import net.md_5.bungee.api.ProxyServer;
import net.md_5.bungee.api.plugin.Plugin;
import org.geysermc.connector.common.serializer.AsteriskSerializer;
import org.geysermc.connector.dump.BootstrapDumpInfo;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
@Getter
public class GeyserBungeeDumpInfo extends BootstrapDumpInfo {
private String platformName;
private String platformVersion;
private boolean onlineMode;
private List<ListenerInfo> listeners;
private List<PluginInfo> plugins;
GeyserBungeeDumpInfo(ProxyServer proxy) {
super();
this.platformName = proxy.getName();
this.platformVersion = proxy.getVersion();
this.onlineMode = proxy.getConfig().isOnlineMode();
this.listeners = new ArrayList<>();
this.plugins = new ArrayList<>();
for (net.md_5.bungee.api.config.ListenerInfo listener : proxy.getConfig().getListeners()) {
String hostname;
if (AsteriskSerializer.showSensitive || (listener.getHost().getHostString().equals("") || listener.getHost().getHostString().equals("0.0.0.0"))) {
hostname = listener.getHost().getHostString();
} else {
hostname = "***";
}
this.listeners.add(new ListenerInfo(hostname, listener.getHost().getPort()));
}
for (Plugin plugin : proxy.getPluginManager().getPlugins()) {
this.plugins.add(new PluginInfo(true, plugin.getDescription().getName(), plugin.getDescription().getVersion(), plugin.getDescription().getMain(), Arrays.asList(plugin.getDescription().getAuthor())));
}
}
}

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2019-2021 GeyserMC. http://geysermc.org
* Copyright (c) 2019-2020 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
@ -25,21 +25,19 @@
package org.geysermc.platform.bungeecord;
import lombok.Getter;
import lombok.Setter;
import org.geysermc.connector.GeyserLogger;
import java.util.logging.Level;
import java.util.logging.Logger;
public class GeyserBungeeLogger implements GeyserLogger {
private final Logger logger;
@Getter @Setter
private boolean debug;
public GeyserBungeeLogger(Logger logger, boolean debug) {
private Logger logger;
private boolean debugMode;
public GeyserBungeeLogger(Logger logger, boolean debugMode) {
this.logger = logger;
this.debug = debug;
this.debugMode = debugMode;
}
@Override
@ -74,8 +72,12 @@ public class GeyserBungeeLogger implements GeyserLogger {
@Override
public void debug(String message) {
if (debug) {
if (debugMode)
info(message);
}
}
@Override
public void setDebug(boolean debug) {
debugMode = debug;
}
}

View File

@ -1,31 +1,32 @@
/*
* Copyright (c) 2019-2021 GeyserMC. http://geysermc.org
* Copyright (c) 2019-2020 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:
* 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 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.
* 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/Geyser
*
* @author GeyserMC
* @link https://github.com/GeyserMC/Geyser
*/
package org.geysermc.platform.bungeecord;
import org.geysermc.connector.common.main.IGeyserMain;
import org.geysermc.common.main.IGeyserMain;
public class GeyserBungeeMain extends IGeyserMain {

View File

@ -1,26 +1,27 @@
/*
* Copyright (c) 2019-2021 GeyserMC. http://geysermc.org
* Copyright (c) 2019-2020 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:
* 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 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.
* 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/Geyser
*
* @author GeyserMC
* @link https://github.com/GeyserMC/Geyser
*/
package org.geysermc.platform.bungeecord;
@ -34,7 +35,7 @@ import net.md_5.bungee.api.connection.PendingConnection;
import net.md_5.bungee.api.event.ProxyPingEvent;
import net.md_5.bungee.api.plugin.Listener;
import net.md_5.bungee.protocol.ProtocolConstants;
import org.geysermc.connector.common.ping.GeyserPingInfo;
import org.geysermc.common.ping.GeyserPingInfo;
import org.geysermc.connector.ping.IGeyserPingPassthrough;
import java.net.Inet4Address;
@ -47,25 +48,26 @@ import java.util.concurrent.CompletableFuture;
@AllArgsConstructor
public class GeyserBungeePingPassthrough implements IGeyserPingPassthrough, Listener {
private static final GeyserPendingConnection PENDING_CONNECTION = new GeyserPendingConnection();
private final ProxyServer proxyServer;
@Override
public GeyserPingInfo getPingInformation(InetSocketAddress inetSocketAddress) {
public GeyserPingInfo getPingInformation() {
CompletableFuture<ProxyPingEvent> future = new CompletableFuture<>();
proxyServer.getPluginManager().callEvent(new ProxyPingEvent(new GeyserPendingConnection(inetSocketAddress), getPingInfo(), (event, throwable) -> {
proxyServer.getPluginManager().callEvent(new ProxyPingEvent(PENDING_CONNECTION, getPingInfo(), (event, throwable) -> {
if (throwable != null) future.completeExceptionally(throwable);
else future.complete(event);
}));
ProxyPingEvent event = future.join();
ServerPing response = event.getResponse();
GeyserPingInfo geyserPingInfo = new GeyserPingInfo(
response.getDescriptionComponent().toLegacyText(),
new GeyserPingInfo.Players(response.getPlayers().getMax(), response.getPlayers().getOnline()),
new GeyserPingInfo.Version(response.getVersion().getName(), response.getVersion().getProtocol())
event.getResponse().getDescription(),
event.getResponse().getPlayers().getOnline(),
event.getResponse().getPlayers().getMax()
);
if (event.getResponse().getPlayers().getSample() != null) {
Arrays.stream(event.getResponse().getPlayers().getSample()).forEach(proxiedPlayer -> {
geyserPingInfo.getPlayerList().add(proxiedPlayer.getName());
geyserPingInfo.addPlayer(proxiedPlayer.getName());
});
}
return geyserPingInfo;
@ -87,12 +89,7 @@ public class GeyserBungeePingPassthrough implements IGeyserPingPassthrough, List
private static class GeyserPendingConnection implements PendingConnection {
private static final UUID FAKE_UUID = UUID.nameUUIDFromBytes("geyser!internal".getBytes());
private final InetSocketAddress remote;
public GeyserPendingConnection(InetSocketAddress remote) {
this.remote = remote;
}
private static final InetSocketAddress FAKE_REMOTE = new InetSocketAddress(Inet4Address.getLoopbackAddress(), 69);
@Override
public String getName() {
@ -146,7 +143,7 @@ public class GeyserBungeePingPassthrough implements IGeyserPingPassthrough, List
@Override
public InetSocketAddress getAddress() {
return remote;
return FAKE_REMOTE;
}
@Override

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2019-2021 GeyserMC. http://geysermc.org
* Copyright (c) 2019-2020 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
@ -27,23 +27,24 @@ package org.geysermc.platform.bungeecord;
import net.md_5.bungee.api.config.ListenerInfo;
import net.md_5.bungee.api.plugin.Plugin;
import net.md_5.bungee.config.Configuration;
import net.md_5.bungee.config.ConfigurationProvider;
import net.md_5.bungee.config.YamlConfiguration;
import org.geysermc.common.PlatformType;
import org.geysermc.connector.GeyserConfiguration;
import org.geysermc.connector.GeyserConnector;
import org.geysermc.connector.bootstrap.GeyserBootstrap;
import org.geysermc.connector.command.CommandManager;
import org.geysermc.connector.configuration.GeyserConfiguration;
import org.geysermc.connector.dump.BootstrapDumpInfo;
import org.geysermc.connector.ping.GeyserLegacyPingPassthrough;
import org.geysermc.connector.ping.IGeyserPingPassthrough;
import org.geysermc.connector.utils.FileUtils;
import org.geysermc.connector.utils.LanguageUtils;
import org.geysermc.platform.bungeecord.command.GeyserBungeeCommandExecutor;
import org.geysermc.platform.bungeecord.command.GeyserBungeeCommandManager;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.net.InetSocketAddress;
import java.nio.file.Path;
import java.nio.file.Files;
import java.util.UUID;
import java.util.logging.Level;
@ -61,48 +62,66 @@ public class GeyserBungeePlugin extends Plugin implements GeyserBootstrap {
if (!getDataFolder().exists())
getDataFolder().mkdir();
try {
if (!getDataFolder().exists())
getDataFolder().mkdir();
File configFile = FileUtils.fileOrCopiedFromResource(new File(getDataFolder(), "config.yml"), "config.yml", (x) -> x.replaceAll("generateduuid", UUID.randomUUID().toString()));
this.geyserConfig = FileUtils.loadConfig(configFile, GeyserBungeeConfiguration.class);
} catch (IOException ex) {
getLogger().log(Level.WARNING, LanguageUtils.getLocaleStringLog("geyser.config.failed"), ex);
ex.printStackTrace();
File file = new File(getDataFolder(), "config.yml");
Configuration configuration = null;
if (!file.exists()) {
try (InputStream in = getResourceAsStream("config.yml")) {
Files.copy(in, file.toPath());
} catch (IOException ex) {
getLogger().log(Level.SEVERE, "Failed to read/create config.yml! Make sure it's up to date and/or readable+writable!", ex);
return;
}
}
try {
configuration = ConfigurationProvider.getProvider(YamlConfiguration.class).load(new File(getDataFolder(), "config.yml"));
} catch(IOException e) {
e.printStackTrace();
}
if (configuration == null) {
getLogger().severe("Failed to read/create config.yml! Make sure it's up to date and/or readable+writable!");
return;
}
this.geyserConfig = new GeyserBungeeConfiguration(getDataFolder(), configuration);
boolean configHasChanged = false;
if (getProxy().getConfig().getListeners().size() == 1) {
ListenerInfo listener = getProxy().getConfig().getListeners().toArray(new ListenerInfo[0])[0];
InetSocketAddress javaAddr = listener.getHost();
// By default this should be localhost but may need to be changed in some circumstances
if (this.geyserConfig.getRemote().getAddress().equalsIgnoreCase("auto")) {
this.geyserConfig.setAutoconfiguredRemote(true);
// Don't use localhost if not listening on all interfaces
if (!javaAddr.getHostString().equals("0.0.0.0") && !javaAddr.getHostString().equals("")) {
this.geyserConfig.getRemote().setAddress(javaAddr.getHostString());
}
this.geyserConfig.getRemote().setPort(javaAddr.getPort());
// Don't change the ip if its listening on all interfaces
// By default this should be 127.0.0.1 but may need to be changed in some circumstances
if (!javaAddr.getHostString().equals("0.0.0.0") && !javaAddr.getHostString().equals("")) {
configuration.set("remote.address", javaAddr.getHostString());
}
if (geyserConfig.getBedrock().isCloneRemotePort()) {
geyserConfig.getBedrock().setPort(javaAddr.getPort());
configuration.set("remote.port", javaAddr.getPort());
configHasChanged = true;
}
if (geyserConfig.getMetrics().getUniqueId().equals("generateduuid")) {
configuration.set("metrics.uuid", UUID.randomUUID().toString());
configHasChanged = true;
}
if (configHasChanged) {
try {
ConfigurationProvider.getProvider(YamlConfiguration.class).save(configuration, new File(getDataFolder(), "config.yml"));
} catch (IOException ex) {
getLogger().log(Level.SEVERE, "Failed to read/create config.yml! Make sure it's up to date and/or readable+writable!", ex);
return;
}
}
this.geyserLogger = new GeyserBungeeLogger(getLogger(), geyserConfig.isDebugMode());
GeyserConfiguration.checkGeyserConfiguration(geyserConfig, geyserLogger);
if (geyserConfig.getRemote().getAuthType().equals("floodgate") && getProxy().getPluginManager().getPlugin("floodgate-bungee") == null) {
geyserLogger.severe(LanguageUtils.getLocaleStringLog("geyser.bootstrap.floodgate.not_installed") + " " + LanguageUtils.getLocaleStringLog("geyser.bootstrap.floodgate.disabling"));
return;
} else if (geyserConfig.isAutoconfiguredRemote() && getProxy().getPluginManager().getPlugin("floodgate-bungee") != null) {
// Floodgate installed means that the user wants Floodgate authentication
geyserLogger.debug("Auto-setting to Floodgate authentication.");
geyserConfig.getRemote().setAuthType("floodgate");
}
geyserConfig.loadFloodgate(this);
this.connector = GeyserConnector.start(PlatformType.BUNGEECORD, this);
@ -142,14 +161,4 @@ public class GeyserBungeePlugin extends Plugin implements GeyserBootstrap {
public IGeyserPingPassthrough getGeyserPingPassthrough() {
return geyserBungeePingPassthrough;
}
@Override
public Path getConfigFolder() {
return getDataFolder().toPath();
}
@Override
public BootstrapDumpInfo getDumpInfo() {
return new GeyserBungeeDumpInfo(getProxy());
}
}

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2019-2021 GeyserMC. http://geysermc.org
* Copyright (c) 2019-2020 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
@ -25,20 +25,17 @@
package org.geysermc.platform.bungeecord.command;
import lombok.AllArgsConstructor;
import net.md_5.bungee.api.chat.TextComponent;
import net.md_5.bungee.api.connection.ProxiedPlayer;
import org.geysermc.connector.command.CommandSender;
import org.geysermc.connector.utils.LanguageUtils;
import org.geysermc.connector.command.CommandSender;
@AllArgsConstructor
public class BungeeCommandSender implements CommandSender {
private final net.md_5.bungee.api.CommandSender handle;
public BungeeCommandSender(net.md_5.bungee.api.CommandSender handle) {
this.handle = handle;
// Ensure even Java players' languages are loaded
LanguageUtils.loadGeyserLocale(getLocale());
}
private net.md_5.bungee.api.CommandSender handle;
@Override
public String getName() {
@ -54,14 +51,4 @@ public class BungeeCommandSender implements CommandSender {
public boolean isConsole() {
return !(handle instanceof ProxiedPlayer);
}
@Override
public String getLocale() {
if (handle instanceof ProxiedPlayer) {
ProxiedPlayer player = (ProxiedPlayer) handle;
String locale = player.getLocale().getLanguage() + "_" + player.getLocale().getCountry();
return LanguageUtils.formatLocale(locale);
}
return LanguageUtils.getDefaultLocale();
}
}

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2019-2021 GeyserMC. http://geysermc.org
* Copyright (c) 2019-2020 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
@ -27,18 +27,19 @@ package org.geysermc.platform.bungeecord.command;
import net.md_5.bungee.api.ChatColor;
import net.md_5.bungee.api.CommandSender;
import net.md_5.bungee.api.chat.TextComponent;
import net.md_5.bungee.api.plugin.Command;
import net.md_5.bungee.api.plugin.TabExecutor;
import org.geysermc.connector.GeyserConnector;
import org.geysermc.connector.command.GeyserCommand;
import org.geysermc.connector.utils.LanguageUtils;
import java.util.ArrayList;
import java.util.Arrays;
public class GeyserBungeeCommandExecutor extends Command implements TabExecutor {
private final GeyserConnector connector;
private GeyserConnector connector;
public GeyserBungeeCommandExecutor(GeyserConnector connector) {
super("geyser");
@ -51,23 +52,20 @@ public class GeyserBungeeCommandExecutor extends Command implements TabExecutor
if (args.length > 0) {
if (getCommand(args[0]) != null) {
if (!sender.hasPermission(getCommand(args[0]).getPermission())) {
BungeeCommandSender commandSender = new BungeeCommandSender(sender);
String message = LanguageUtils.getPlayerLocaleString("geyser.bootstrap.command.permission_fail", commandSender.getLocale());
commandSender.sendMessage(ChatColor.RED + message);
sender.sendMessage(TextComponent.fromLegacyText(ChatColor.RED + "You do not have permission to execute this command!"));
return;
}
getCommand(args[0]).execute(new BungeeCommandSender(sender), args.length > 1 ? Arrays.copyOfRange(args, 1, args.length) : new String[0]);
getCommand(args[0]).execute(new BungeeCommandSender(sender), args);
}
} else {
getCommand("help").execute(new BungeeCommandSender(sender), new String[0]);
getCommand("help").execute(new BungeeCommandSender(sender), args);
}
}
@Override
public Iterable<String> onTabComplete(CommandSender sender, String[] args) {
if (args.length == 1) {
return connector.getCommandManager().getCommandNames();
return Arrays.asList("?", "help", "reload", "shutdown", "stop");
}
return new ArrayList<>();
}

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2019-2021 GeyserMC. http://geysermc.org
* Copyright (c) 2019-2020 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

View File

@ -6,11 +6,12 @@
<parent>
<groupId>org.geysermc</groupId>
<artifactId>geyser-parent</artifactId>
<version>1.2.0-SNAPSHOT</version>
<version>parent</version>
<relativePath>../</relativePath>
</parent>
<artifactId>bootstrap-parent</artifactId>
<version>1.0-SNAPSHOT</version>
<packaging>pom</packaging>
<repositories>
<repository>
<id>spigot-public</id>
@ -34,8 +35,8 @@
</repository>
</repositories>
<modules>
<module>bukkit</module>
<module>bungeecord</module>
<module>spigot</module>
<module>sponge</module>
<module>standalone</module>
<module>velocity</module>

View File

@ -1,56 +0,0 @@
/*
* Copyright (c) 2019-2021 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/Geyser
*/
package org.geysermc.platform.spigot;
import com.fasterxml.jackson.annotation.JsonIgnore;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import lombok.Getter;
import org.bukkit.Bukkit;
import org.bukkit.plugin.Plugin;
import org.geysermc.connector.FloodgateKeyLoader;
import org.geysermc.connector.configuration.GeyserJacksonConfiguration;
import java.nio.file.Path;
@Getter
@JsonIgnoreProperties(ignoreUnknown = true)
public final class GeyserSpigotConfiguration extends GeyserJacksonConfiguration {
@JsonIgnore
private Path floodgateKeyPath;
public void loadFloodgate(GeyserSpigotPlugin plugin) {
Plugin floodgate = Bukkit.getPluginManager().getPlugin("floodgate-bukkit");
Path geyserDataFolder = plugin.getDataFolder().toPath();
Path floodgateDataFolder = floodgate != null ? floodgate.getDataFolder().toPath() : null;
floodgateKeyPath = FloodgateKeyLoader.getKeyPath(this, floodgate, floodgateDataFolder, geyserDataFolder, plugin.getGeyserLogger());
}
@Override
public boolean isCacheChunks() {
return true; // We override this as with Bukkit, we have direct access to the server implementation
}
}

View File

@ -1,66 +0,0 @@
/*
* Copyright (c) 2019-2021 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/Geyser
*/
package org.geysermc.platform.spigot;
import lombok.Getter;
import org.bukkit.Bukkit;
import org.bukkit.plugin.Plugin;
import org.geysermc.connector.common.serializer.AsteriskSerializer;
import org.geysermc.connector.dump.BootstrapDumpInfo;
import java.util.ArrayList;
import java.util.List;
@Getter
public class GeyserSpigotDumpInfo extends BootstrapDumpInfo {
private String platformName;
private String platformVersion;
private String platformAPIVersion;
private boolean onlineMode;
private String serverIP;
private int serverPort;
private List<PluginInfo> plugins;
GeyserSpigotDumpInfo() {
super();
this.platformName = Bukkit.getName();
this.platformVersion = Bukkit.getVersion();
this.platformAPIVersion = Bukkit.getBukkitVersion();
this.onlineMode = Bukkit.getOnlineMode();
if (AsteriskSerializer.showSensitive || (Bukkit.getIp().equals("") || Bukkit.getIp().equals("0.0.0.0"))) {
this.serverIP = Bukkit.getIp();
} else {
this.serverIP = "***";
}
this.serverPort = Bukkit.getPort();
this.plugins = new ArrayList<>();
for (Plugin plugin : Bukkit.getPluginManager().getPlugins()) {
this.plugins.add(new PluginInfo(plugin.isEnabled(), plugin.getName(), plugin.getDescription().getVersion(), plugin.getDescription().getMain(), plugin.getDescription().getAuthors()));
}
}
}

View File

@ -1,81 +0,0 @@
/*
* Copyright (c) 2019-2021 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/Geyser
*/
package org.geysermc.platform.spigot;
import com.github.steveice10.mc.protocol.MinecraftConstants;
import lombok.AllArgsConstructor;
import org.bukkit.Bukkit;
import org.bukkit.entity.Player;
import org.bukkit.event.server.ServerListPingEvent;
import org.bukkit.util.CachedServerIcon;
import org.geysermc.connector.common.ping.GeyserPingInfo;
import org.geysermc.connector.ping.IGeyserPingPassthrough;
import java.net.InetAddress;
import java.net.InetSocketAddress;
import java.util.Collections;
import java.util.Iterator;
@AllArgsConstructor
public class GeyserSpigotPingPassthrough implements IGeyserPingPassthrough {
private final GeyserSpigotLogger logger;
@Override
public GeyserPingInfo getPingInformation(InetSocketAddress inetSocketAddress) {
try {
ServerListPingEvent event = new GeyserPingEvent(inetSocketAddress.getAddress(), Bukkit.getMotd(), Bukkit.getOnlinePlayers().size(), Bukkit.getMaxPlayers());
Bukkit.getPluginManager().callEvent(event);
GeyserPingInfo geyserPingInfo = new GeyserPingInfo(event.getMotd(),
new GeyserPingInfo.Players(event.getMaxPlayers(), event.getNumPlayers()),
new GeyserPingInfo.Version(Bukkit.getVersion(), MinecraftConstants.PROTOCOL_VERSION) // thanks Spigot for not exposing this, just default to latest
);
Bukkit.getOnlinePlayers().stream().map(Player::getName).forEach(geyserPingInfo.getPlayerList()::add);
return geyserPingInfo;
} catch (Exception e) {
logger.debug("Error while getting Bukkit ping passthrough: " + e.toString());
return new GeyserPingInfo(null, null, null);
}
}
// These methods are unimplemented on spigot api by default so we add stubs so plugins don't complain
private static class GeyserPingEvent extends ServerListPingEvent {
public GeyserPingEvent(InetAddress address, String motd, int numPlayers, int maxPlayers) {
super(address, motd, numPlayers, maxPlayers);
}
@Override
public void setServerIcon(CachedServerIcon icon) throws IllegalArgumentException, UnsupportedOperationException {
}
@Override
public Iterator<Player> iterator() throws UnsupportedOperationException {
return Collections.EMPTY_LIST.iterator();
}
}
}

View File

@ -1,308 +0,0 @@
/*
* Copyright (c) 2019-2021 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/Geyser
*/
package org.geysermc.platform.spigot;
import com.github.steveice10.mc.protocol.MinecraftConstants;
import org.bukkit.Bukkit;
import org.bukkit.plugin.java.JavaPlugin;
import org.geysermc.adapters.spigot.SpigotAdapters;
import org.geysermc.common.PlatformType;
import org.geysermc.connector.GeyserConnector;
import org.geysermc.connector.bootstrap.GeyserBootstrap;
import org.geysermc.connector.command.CommandManager;
import org.geysermc.connector.configuration.GeyserConfiguration;
import org.geysermc.connector.dump.BootstrapDumpInfo;
import org.geysermc.connector.network.translators.world.WorldManager;
import org.geysermc.connector.ping.GeyserLegacyPingPassthrough;
import org.geysermc.connector.ping.IGeyserPingPassthrough;
import org.geysermc.connector.utils.FileUtils;
import org.geysermc.connector.utils.LanguageUtils;
import org.geysermc.platform.spigot.command.GeyserSpigotCommandExecutor;
import org.geysermc.platform.spigot.command.GeyserSpigotCommandManager;
import org.geysermc.platform.spigot.command.SpigotCommandSender;
import org.geysermc.platform.spigot.world.GeyserSpigotBlockPlaceListener;
import org.geysermc.platform.spigot.world.manager.*;
import us.myles.ViaVersion.api.Pair;
import us.myles.ViaVersion.api.Via;
import us.myles.ViaVersion.api.data.MappingData;
import us.myles.ViaVersion.api.protocol.Protocol;
import us.myles.ViaVersion.api.protocol.ProtocolRegistry;
import us.myles.ViaVersion.api.protocol.ProtocolVersion;
import java.io.File;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.List;
import java.util.UUID;
import java.util.logging.Level;
public class GeyserSpigotPlugin extends JavaPlugin implements GeyserBootstrap {
private GeyserSpigotCommandManager geyserCommandManager;
private GeyserSpigotConfiguration geyserConfig;
private GeyserSpigotLogger geyserLogger;
private IGeyserPingPassthrough geyserSpigotPingPassthrough;
private GeyserSpigotWorldManager geyserWorldManager;
private GeyserConnector connector;
@Override
public void onEnable() {
// This is manually done instead of using Bukkit methods to save the config because otherwise comments get removed
try {
if (!getDataFolder().exists()) {
getDataFolder().mkdir();
File bukkitConfig = new File("plugins/Geyser-Bukkit/config.yml");
if (bukkitConfig.exists()) { // Copy over old configs
getLogger().log(Level.INFO, LanguageUtils.getLocaleStringLog("geyser.bootstrap.config.copy_bukkit_config"));
Files.copy(bukkitConfig.toPath(), new File(getDataFolder().toString() + "/config.yml").toPath());
getLogger().log(Level.INFO, LanguageUtils.getLocaleStringLog("geyser.bootstrap.config.copied_bukkit_config"));
}
}
File configFile = FileUtils.fileOrCopiedFromResource(new File(getDataFolder(), "config.yml"), "config.yml", (x) -> x.replaceAll("generateduuid", UUID.randomUUID().toString()));
this.geyserConfig = FileUtils.loadConfig(configFile, GeyserSpigotConfiguration.class);
} catch (IOException ex) {
getLogger().log(Level.WARNING, LanguageUtils.getLocaleStringLog("geyser.config.failed"), ex);
ex.printStackTrace();
}
// By default this should be localhost but may need to be changed in some circumstances
if (this.geyserConfig.getRemote().getAddress().equalsIgnoreCase("auto")) {
geyserConfig.setAutoconfiguredRemote(true);
// Don't use localhost if not listening on all interfaces
if (!Bukkit.getIp().equals("0.0.0.0") && !Bukkit.getIp().equals("")) {
geyserConfig.getRemote().setAddress(Bukkit.getIp());
}
geyserConfig.getRemote().setPort(Bukkit.getPort());
}
if (geyserConfig.getBedrock().isCloneRemotePort()) {
geyserConfig.getBedrock().setPort(Bukkit.getPort());
}
this.geyserLogger = new GeyserSpigotLogger(getLogger(), geyserConfig.isDebugMode());
GeyserConfiguration.checkGeyserConfiguration(geyserConfig, geyserLogger);
if (geyserConfig.getRemote().getAuthType().equals("floodgate") && Bukkit.getPluginManager().getPlugin("floodgate-bukkit") == null) {
geyserLogger.severe(LanguageUtils.getLocaleStringLog("geyser.bootstrap.floodgate.not_installed") + " " + LanguageUtils.getLocaleStringLog("geyser.bootstrap.floodgate.disabling"));
this.getPluginLoader().disablePlugin(this);
return;
} else if (geyserConfig.isAutoconfiguredRemote() && Bukkit.getPluginManager().getPlugin("floodgate-bukkit") != null) {
// Floodgate installed means that the user wants Floodgate authentication
geyserLogger.debug("Auto-setting to Floodgate authentication.");
geyserConfig.getRemote().setAuthType("floodgate");
}
geyserConfig.loadFloodgate(this);
this.connector = GeyserConnector.start(PlatformType.SPIGOT, this);
if (geyserConfig.isLegacyPingPassthrough()) {
this.geyserSpigotPingPassthrough = GeyserLegacyPingPassthrough.init(connector);
} else {
this.geyserSpigotPingPassthrough = new GeyserSpigotPingPassthrough(geyserLogger);
}
this.geyserCommandManager = new GeyserSpigotCommandManager(this, connector);
boolean isViaVersion = (Bukkit.getPluginManager().getPlugin("ViaVersion") != null);
if (isViaVersion) {
if (!isCompatible(Via.getAPI().getVersion().replace("-SNAPSHOT", ""), "3.2.0")) {
geyserLogger.warning(LanguageUtils.getLocaleStringLog("geyser.bootstrap.viaversion.too_old",
"https://ci.viaversion.com/job/ViaVersion/"));
isViaVersion = false;
}
}
// Used to determine if Block.getBlockData() is present.
boolean isLegacy = !isCompatible(Bukkit.getServer().getVersion(), "1.13.0");
if (isLegacy)
geyserLogger.debug("Legacy version of Minecraft (1.12.2 or older) detected; falling back to ViaVersion for block state retrieval.");
boolean use3dBiomes = isCompatible(Bukkit.getServer().getVersion(), "1.16.0");
if (!use3dBiomes) {
geyserLogger.debug("Legacy version of Minecraft (1.15.2 or older) detected; not using 3D biomes.");
}
// Set if we need to use a different method for getting a player's locale
SpigotCommandSender.setUseLegacyLocaleMethod(!isCompatible(Bukkit.getServer().getVersion(), "1.12.0"));
if (connector.getConfig().isUseAdapters()) {
try {
String name = Bukkit.getServer().getClass().getPackage().getName();
String nmsVersion = name.substring(name.lastIndexOf('.') + 1);
SpigotAdapters.registerWorldAdapter(nmsVersion);
if (isViaVersion && isViaVersionNeeded()) {
if (isLegacy) {
// Pre-1.13
this.geyserWorldManager = new GeyserSpigot1_12NativeWorldManager();
} else {
// Post-1.13
this.geyserWorldManager = new GeyserSpigotLegacyNativeWorldManager(this, use3dBiomes);
}
} else {
// No ViaVersion
this.geyserWorldManager = new GeyserSpigotNativeWorldManager(use3dBiomes);
}
geyserLogger.debug("Using NMS adapter: " + this.geyserWorldManager.getClass() + ", " + nmsVersion);
} catch (Exception e) {
if (geyserConfig.isDebugMode()) {
geyserLogger.debug("Error while attempting to find NMS adapter. Most likely, this can be safely ignored. :)");
e.printStackTrace();
}
}
} else {
geyserLogger.debug("Not using NMS adapter as it is disabled in the config.");
}
if (this.geyserWorldManager == null) {
// No NMS adapter
if (isLegacy && isViaVersion) {
// Use ViaVersion for converting pre-1.13 block states
this.geyserWorldManager = new GeyserSpigot1_12WorldManager();
} else if (isLegacy) {
// Not sure how this happens - without ViaVersion, we don't know any block states, so just assume everything is air
this.geyserWorldManager = new GeyserSpigotFallbackWorldManager();
} else {
// Post-1.13
this.geyserWorldManager = new GeyserSpigotWorldManager(use3dBiomes);
}
geyserLogger.debug("Using default world manager: " + this.geyserWorldManager.getClass());
}
GeyserSpigotBlockPlaceListener blockPlaceListener = new GeyserSpigotBlockPlaceListener(connector, this.geyserWorldManager);
Bukkit.getServer().getPluginManager().registerEvents(blockPlaceListener, this);
this.getCommand("geyser").setExecutor(new GeyserSpigotCommandExecutor(connector));
}
@Override
public void onDisable() {
if (connector != null) {
connector.shutdown();
}
}
@Override
public GeyserSpigotConfiguration getGeyserConfig() {
return geyserConfig;
}
@Override
public GeyserSpigotLogger getGeyserLogger() {
return geyserLogger;
}
@Override
public CommandManager getGeyserCommandManager() {
return this.geyserCommandManager;
}
@Override
public IGeyserPingPassthrough getGeyserPingPassthrough() {
return geyserSpigotPingPassthrough;
}
@Override
public WorldManager getWorldManager() {
return this.geyserWorldManager;
}
@Override
public Path getConfigFolder() {
return getDataFolder().toPath();
}
@Override
public BootstrapDumpInfo getDumpInfo() {
return new GeyserSpigotDumpInfo();
}
public boolean isCompatible(String version, String whichVersion) {
int[] currentVersion = parseVersion(version);
int[] otherVersion = parseVersion(whichVersion);
int length = Math.max(currentVersion.length, otherVersion.length);
for (int index = 0; index < length; index = index + 1) {
int self = (index < currentVersion.length) ? currentVersion[index] : 0;
int other = (index < otherVersion.length) ? otherVersion[index] : 0;
if (self != other) {
return (self - other) > 0;
}
}
return true;
}
private int[] parseVersion(String versionParam) {
versionParam = (versionParam == null) ? "" : versionParam;
if (versionParam.contains("(MC: ")) {
versionParam = versionParam.split("\\(MC: ")[1];
versionParam = versionParam.split("\\)")[0];
}
String[] stringArray = versionParam.split("[_.-]");
int[] temp = new int[stringArray.length];
for (int index = 0; index <= (stringArray.length - 1); index = index + 1) {
String t = stringArray[index].replaceAll("\\D", "");
try {
temp[index] = Integer.parseInt(t);
} catch (NumberFormatException ex) {
temp[index] = 0;
}
}
return temp;
}
/**
* @return the server version before ViaVersion finishes initializing
*/
public ProtocolVersion getServerProtocolVersion() {
String bukkitVersion = Bukkit.getServer().getVersion();
// Turn "(MC: 1.16.4)" into 1.16.4.
String version = bukkitVersion.split("\\(MC: ")[1].split("\\)")[0];
return ProtocolVersion.getClosest(version);
}
/**
* This function should not run unless ViaVersion is installed on the server.
*
* @return true if there is any block mappings difference between the server and client.
*/
private boolean isViaVersionNeeded() {
ProtocolVersion serverVersion = getServerProtocolVersion();
List<Pair<Integer, Protocol>> protocolList = ProtocolRegistry.getProtocolPath(MinecraftConstants.PROTOCOL_VERSION,
serverVersion.getVersion());
if (protocolList == null) {
// No translation needed!
return false;
}
for (int i = protocolList.size() - 1; i >= 0; i--) {
MappingData mappingData = protocolList.get(i).getValue().getMappingData();
if (mappingData != null) {
return true;
}
}
// All mapping data is null, which means client and server block states are the same
return false;
}
}

View File

@ -1,115 +0,0 @@
/*
* Copyright (c) 2019-2021 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/Geyser
*/
package org.geysermc.platform.spigot.command;
import org.bukkit.command.ConsoleCommandSender;
import org.bukkit.entity.Player;
import org.geysermc.connector.GeyserConnector;
import org.geysermc.connector.command.CommandSender;
import org.geysermc.connector.utils.LanguageUtils;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
public class SpigotCommandSender implements CommandSender {
/**
* Whether to use {@code Player.getLocale()} or {@code Player.spigot().getLocale()}, depending on version.
* 1.12 or greater should not use the legacy method.
*/
private static boolean USE_LEGACY_METHOD = false;
private static Method LOCALE_METHOD;
private final org.bukkit.command.CommandSender handle;
private final String locale;
public SpigotCommandSender(org.bukkit.command.CommandSender handle) {
this.handle = handle;
this.locale = getSpigotLocale();
// Ensure even Java players' languages are loaded
LanguageUtils.loadGeyserLocale(locale);
}
@Override
public String getName() {
return handle.getName();
}
@Override
public void sendMessage(String message) {
handle.sendMessage(message);
}
@Override
public boolean isConsole() {
return handle instanceof ConsoleCommandSender;
}
@Override
public String getLocale() {
return locale;
}
/**
* Set if we are on pre-1.12, and therefore {@code player.getLocale()} doesn't exist and we have to get
* {@code player.spigot().getLocale()}.
*
* @param useLegacyMethod if we are running pre-1.12 and therefore need to use reflection to get the player locale
*/
public static void setUseLegacyLocaleMethod(boolean useLegacyMethod) {
USE_LEGACY_METHOD = useLegacyMethod;
if (USE_LEGACY_METHOD) {
try {
//noinspection JavaReflectionMemberAccess - of course it doesn't exist; that's why we're doing it
LOCALE_METHOD = Player.Spigot.class.getMethod("getLocale");
} catch (NoSuchMethodException e) {
GeyserConnector.getInstance().getLogger().debug("Player.Spigot.getLocale() doesn't exist? Not a big deal but if you're seeing this please report it to the developers!");
}
}
}
/**
* So we only have to do nasty reflection stuff once per command
*
* @return the locale of the Spigot player
*/
private String getSpigotLocale() {
if (handle instanceof Player) {
Player player = (Player) handle;
if (USE_LEGACY_METHOD) {
try {
// sigh
// This was the only option on older Spigot instances and now it's gone
return (String) LOCALE_METHOD.invoke(player.spigot());
} catch (IllegalAccessException | InvocationTargetException ignored) {
}
} else {
return player.getLocale();
}
}
return LanguageUtils.getDefaultLocale();
}
}

View File

@ -1,71 +0,0 @@
/*
* Copyright (c) 2019-2021 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/Geyser
*/
package org.geysermc.platform.spigot.world;
import com.nukkitx.math.vector.Vector3f;
import com.nukkitx.protocol.bedrock.data.SoundEvent;
import com.nukkitx.protocol.bedrock.packet.LevelSoundEventPacket;
import lombok.AllArgsConstructor;
import org.bukkit.Bukkit;
import org.bukkit.event.EventHandler;
import org.bukkit.event.Listener;
import org.bukkit.event.block.BlockPlaceEvent;
import org.geysermc.connector.GeyserConnector;
import org.geysermc.connector.network.session.GeyserSession;
import org.geysermc.connector.network.translators.world.block.BlockTranslator;
import org.geysermc.platform.spigot.world.manager.GeyserSpigotWorldManager;
@AllArgsConstructor
public class GeyserSpigotBlockPlaceListener implements Listener {
private final GeyserConnector connector;
private final GeyserSpigotWorldManager worldManager;
@EventHandler
public void place(final BlockPlaceEvent event) {
for (GeyserSession session : connector.getPlayers()) {
if (event.getPlayer() == Bukkit.getPlayer(session.getPlayerEntity().getUsername())) {
LevelSoundEventPacket placeBlockSoundPacket = new LevelSoundEventPacket();
placeBlockSoundPacket.setSound(SoundEvent.PLACE);
placeBlockSoundPacket.setPosition(Vector3f.from(event.getBlockPlaced().getX(), event.getBlockPlaced().getY(), event.getBlockPlaced().getZ()));
placeBlockSoundPacket.setBabySound(false);
if (worldManager.isLegacy()) {
placeBlockSoundPacket.setExtraData(BlockTranslator.getBedrockBlockId(worldManager.getBlockAt(session,
event.getBlockPlaced().getX(), event.getBlockPlaced().getY(), event.getBlockPlaced().getZ())));
} else {
String javaBlockId = event.getBlockPlaced().getBlockData().getAsString();
placeBlockSoundPacket.setExtraData(BlockTranslator.getBedrockBlockId(BlockTranslator.getJavaIdBlockMap().getOrDefault(javaBlockId, BlockTranslator.JAVA_AIR_ID)));
}
placeBlockSoundPacket.setIdentifier(":");
session.sendUpstreamPacket(placeBlockSoundPacket);
session.setLastBlockPlacePosition(null);
session.setLastBlockPlacedId(null);
break;
}
}
}
}

View File

@ -1,59 +0,0 @@
/*
* Copyright (c) 2019-2021 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/Geyser
*/
package org.geysermc.platform.spigot.world.manager;
import org.bukkit.Bukkit;
import org.bukkit.entity.Player;
import org.geysermc.adapters.spigot.SpigotAdapters;
import org.geysermc.adapters.spigot.SpigotWorldAdapter;
import org.geysermc.connector.network.session.GeyserSession;
import org.geysermc.connector.network.translators.world.block.BlockTranslator;
import us.myles.ViaVersion.api.Via;
import us.myles.ViaVersion.protocols.protocol1_13to1_12_2.storage.BlockStorage;
/**
* Used with ViaVersion and pre-1.13.
*/
public class GeyserSpigot1_12NativeWorldManager extends GeyserSpigot1_12WorldManager {
private final SpigotWorldAdapter adapter;
public GeyserSpigot1_12NativeWorldManager() {
this.adapter = SpigotAdapters.getWorldAdapter();
// Unlike post-1.13, we can't build up a cache of block states, because block entities need some special conversion
}
@Override
public int getBlockAt(GeyserSession session, int x, int y, int z) {
Player player = Bukkit.getPlayer(session.getPlayerEntity().getUsername());
if (player == null) {
return BlockTranslator.JAVA_AIR_ID;
}
// Get block entity storage
BlockStorage storage = Via.getManager().getConnection(player.getUniqueId()).get(BlockStorage.class);
int blockId = adapter.getBlockAt(player.getWorld(), x, y, z);
return getLegacyBlock(storage, blockId, x, y, z);
}
}

View File

@ -1,141 +0,0 @@
/*
* Copyright (c) 2019-2021 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/Geyser
*/
package org.geysermc.platform.spigot.world.manager;
import com.github.steveice10.mc.protocol.data.game.chunk.Chunk;
import org.bukkit.Bukkit;
import org.bukkit.World;
import org.bukkit.block.Block;
import org.bukkit.entity.Player;
import org.geysermc.connector.network.session.GeyserSession;
import org.geysermc.connector.network.translators.world.block.BlockTranslator;
import us.myles.ViaVersion.api.Pair;
import us.myles.ViaVersion.api.Via;
import us.myles.ViaVersion.api.data.MappingData;
import us.myles.ViaVersion.api.minecraft.Position;
import us.myles.ViaVersion.api.protocol.Protocol;
import us.myles.ViaVersion.api.protocol.ProtocolRegistry;
import us.myles.ViaVersion.api.protocol.ProtocolVersion;
import us.myles.ViaVersion.protocols.protocol1_13to1_12_2.Protocol1_13To1_12_2;
import us.myles.ViaVersion.protocols.protocol1_13to1_12_2.storage.BlockStorage;
import java.util.List;
/**
* Should be used when ViaVersion is present, no NMS adapter is being used, and we are pre-1.13.
*
* You need ViaVersion to connect to an older server with the Geyser-Spigot plugin.
*/
public class GeyserSpigot1_12WorldManager extends GeyserSpigotWorldManager {
/**
* Specific mapping data for 1.12 to 1.13. Used to convert the 1.12 block into the 1.13 block state.
* (Block IDs did not change between server versions until 1.13 and after)
*/
private final MappingData mappingData1_12to1_13;
/**
* The list of all protocols from the client's version to 1.13.
*/
private final List<Pair<Integer, Protocol>> protocolList;
public GeyserSpigot1_12WorldManager() {
super(false);
this.mappingData1_12to1_13 = ProtocolRegistry.getProtocol(Protocol1_13To1_12_2.class).getMappingData();
this.protocolList = ProtocolRegistry.getProtocolPath(CLIENT_PROTOCOL_VERSION,
ProtocolVersion.v1_13.getVersion());
}
@Override
@SuppressWarnings("deprecation")
public int getBlockAt(GeyserSession session, int x, int y, int z) {
Player player = Bukkit.getPlayer(session.getPlayerEntity().getUsername());
if (player == null) {
return BlockTranslator.JAVA_AIR_ID;
}
// Get block entity storage
BlockStorage storage = Via.getManager().getConnection(player.getUniqueId()).get(BlockStorage.class);
Block block = player.getWorld().getBlockAt(x, y, z);
// Black magic that gets the old block state ID
int blockId = (block.getType().getId() << 4) | (block.getData() & 0xF);
return getLegacyBlock(storage, blockId, x, y, z);
}
/**
*
* @param storage ViaVersion's block entity storage (used to fix block entity state differences)
* @param blockId the pre-1.13 block id
* @param x X coordinate of block
* @param y Y coordinate of block
* @param z Z coordinate of block
* @return the block state updated to the latest Minecraft version
*/
@SuppressWarnings("deprecation")
public int getLegacyBlock(BlockStorage storage, int blockId, int x, int y, int z) {
// Convert block state from old version (1.12.2) -> 1.13 -> 1.13.1 -> 1.14 -> 1.15 -> 1.16 -> 1.16.2
blockId = mappingData1_12to1_13.getNewBlockId(blockId);
// Translate block entity differences - some information was stored in block tags and not block states
if (storage.isWelcome(blockId)) { // No getOrDefault method
BlockStorage.ReplacementData data = storage.get(new Position(x, (short) y, z));
if (data != null && data.getReplacement() != -1) {
blockId = data.getReplacement();
}
}
for (int i = protocolList.size() - 1; i >= 0; i--) {
MappingData mappingData = protocolList.get(i).getValue().getMappingData();
if (mappingData != null) {
blockId = mappingData.getNewBlockStateId(blockId);
}
}
return blockId;
}
@SuppressWarnings("deprecation")
@Override
public void getBlocksInSection(GeyserSession session, int x, int y, int z, Chunk chunk) {
Player player = Bukkit.getPlayer(session.getPlayerEntity().getUsername());
if (player == null) {
return;
}
World world = player.getWorld();
// Get block entity storage
BlockStorage storage = Via.getManager().getConnection(player.getUniqueId()).get(BlockStorage.class);
for (int blockY = 0; blockY < 16; blockY++) { // Cache-friendly iteration order
for (int blockZ = 0; blockZ < 16; blockZ++) {
for (int blockX = 0; blockX < 16; blockX++) {
Block block = world.getBlockAt((x << 4) + blockX, (y << 4) + blockY, (z << 4) + blockZ);
// Black magic that gets the old block state ID
int blockId = (block.getType().getId() << 4) | (block.getData() & 0xF);
chunk.set(blockX, blockY, blockZ, getLegacyBlock(storage, blockId, (x << 4) + blockX, (y << 4) + blockY, (z << 4) + blockZ));
}
}
}
}
@Override
public boolean isLegacy() {
return true;
}
}

View File

@ -1,62 +0,0 @@
/*
* Copyright (c) 2019-2021 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/Geyser
*/
package org.geysermc.platform.spigot.world.manager;
import com.github.steveice10.mc.protocol.data.game.chunk.Chunk;
import org.geysermc.connector.network.session.GeyserSession;
import org.geysermc.connector.network.translators.world.block.BlockTranslator;
/**
* Should only be used when we know {@link GeyserSpigotWorldManager#getBlockAt(GeyserSession, int, int, int)}
* cannot be accurate. Typically, this is when ViaVersion is not installed but a client still manages to connect.
* If this occurs to you somehow, please let us know!!
*/
public class GeyserSpigotFallbackWorldManager extends GeyserSpigotWorldManager {
public GeyserSpigotFallbackWorldManager() {
// Since this is pre-1.13 (and thus pre-1.15), there will never be 3D biomes.
super(false);
}
@Override
public int getBlockAt(GeyserSession session, int x, int y, int z) {
return BlockTranslator.JAVA_AIR_ID;
}
@Override
public void getBlocksInSection(GeyserSession session, int x, int y, int z, Chunk chunk) {
// Do nothing, since we can't do anything with the chunk
}
@Override
public boolean hasMoreBlockDataThanChunkCache() {
return false;
}
@Override
public boolean isLegacy() {
return true;
}
}

View File

@ -1,79 +0,0 @@
/*
* Copyright (c) 2019-2021 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/Geyser
*/
package org.geysermc.platform.spigot.world.manager;
import com.github.steveice10.mc.protocol.MinecraftConstants;
import it.unimi.dsi.fastutil.ints.Int2IntMap;
import it.unimi.dsi.fastutil.ints.Int2IntOpenHashMap;
import it.unimi.dsi.fastutil.ints.IntList;
import org.geysermc.connector.network.session.GeyserSession;
import org.geysermc.platform.spigot.GeyserSpigotPlugin;
import us.myles.ViaVersion.api.Pair;
import us.myles.ViaVersion.api.data.MappingData;
import us.myles.ViaVersion.api.protocol.Protocol;
import us.myles.ViaVersion.api.protocol.ProtocolRegistry;
import us.myles.ViaVersion.api.protocol.ProtocolVersion;
import java.util.List;
/**
* Used when block IDs need to be translated to the latest version
*/
public class GeyserSpigotLegacyNativeWorldManager extends GeyserSpigotNativeWorldManager {
private final Int2IntMap oldToNewBlockId;
public GeyserSpigotLegacyNativeWorldManager(GeyserSpigotPlugin plugin, boolean use3dBiomes) {
super(use3dBiomes);
IntList allBlockStates = adapter.getAllBlockStates();
oldToNewBlockId = new Int2IntOpenHashMap(allBlockStates.size());
ProtocolVersion serverVersion = plugin.getServerProtocolVersion();
List<Pair<Integer, Protocol>> protocolList = ProtocolRegistry.getProtocolPath(MinecraftConstants.PROTOCOL_VERSION,
serverVersion.getVersion());
for (int oldBlockId : allBlockStates) {
int newBlockId = oldBlockId;
// protocolList should *not* be null; we checked for that before initializing this class
for (int i = protocolList.size() - 1; i >= 0; i--) {
MappingData mappingData = protocolList.get(i).getValue().getMappingData();
if (mappingData != null) {
newBlockId = mappingData.getNewBlockStateId(newBlockId);
}
}
oldToNewBlockId.put(oldBlockId, newBlockId);
}
}
@Override
public int getBlockAt(GeyserSession session, int x, int y, int z) {
int nativeBlockId = super.getBlockAt(session, x, y, z);
return oldToNewBlockId.getOrDefault(nativeBlockId, nativeBlockId);
}
@Override
public boolean isLegacy() {
return true;
}
}

View File

@ -1,51 +0,0 @@
/*
* Copyright (c) 2019-2021 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/Geyser
*/
package org.geysermc.platform.spigot.world.manager;
import org.bukkit.Bukkit;
import org.bukkit.entity.Player;
import org.geysermc.adapters.spigot.SpigotAdapters;
import org.geysermc.adapters.spigot.SpigotWorldAdapter;
import org.geysermc.connector.network.session.GeyserSession;
import org.geysermc.connector.network.translators.world.block.BlockTranslator;
public class GeyserSpigotNativeWorldManager extends GeyserSpigotWorldManager {
protected final SpigotWorldAdapter adapter;
public GeyserSpigotNativeWorldManager(boolean use3dBiomes) {
super(use3dBiomes);
adapter = SpigotAdapters.getWorldAdapter();
}
@Override
public int getBlockAt(GeyserSession session, int x, int y, int z) {
Player player = Bukkit.getPlayer(session.getPlayerEntity().getUsername());
if (player == null) {
return BlockTranslator.JAVA_AIR_ID;
}
return adapter.getBlockAt(player.getWorld(), x, y, z);
}
}

View File

@ -1,195 +0,0 @@
/*
* Copyright (c) 2019-2021 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/Geyser
*/
package org.geysermc.platform.spigot.world.manager;
import com.fasterxml.jackson.databind.JsonNode;
import com.github.steveice10.mc.protocol.MinecraftConstants;
import com.github.steveice10.mc.protocol.data.game.chunk.Chunk;
import it.unimi.dsi.fastutil.ints.Int2IntMap;
import it.unimi.dsi.fastutil.ints.Int2IntOpenHashMap;
import org.bukkit.Bukkit;
import org.bukkit.World;
import org.bukkit.block.Biome;
import org.bukkit.block.Block;
import org.bukkit.block.data.BlockData;
import org.bukkit.entity.Player;
import org.geysermc.connector.GeyserConnector;
import org.geysermc.connector.network.session.GeyserSession;
import org.geysermc.connector.network.translators.world.GeyserWorldManager;
import org.geysermc.connector.network.translators.world.block.BlockTranslator;
import org.geysermc.connector.utils.FileUtils;
import org.geysermc.connector.utils.GameRule;
import org.geysermc.connector.utils.LanguageUtils;
import java.io.InputStream;
/**
* The base world manager to use when there is no supported NMS revision
*/
public class GeyserSpigotWorldManager extends GeyserWorldManager {
/**
* The current client protocol version for ViaVersion usage.
*/
protected static final int CLIENT_PROTOCOL_VERSION = MinecraftConstants.PROTOCOL_VERSION;
/**
* Whether the server is pre-1.16 and therefore does not support 3D biomes on an API level guaranteed.
*/
private final boolean use3dBiomes;
/**
* Stores a list of {@link Biome} ordinal numbers to Minecraft biome numeric IDs.
*
* Working with the Biome enum in Spigot poses two problems:
* 1: The Biome enum values change in both order and names over the years.
* 2: There is no way to get the Minecraft biome ID from the name itself with Spigot.
* To solve both of these problems, we store a JSON file of every Biome enum that has existed,
* along with its 1.16 biome number.
*
* The key is the Spigot Biome ordinal; the value is the Minecraft Java biome numerical ID
*/
private final Int2IntMap biomeToIdMap = new Int2IntOpenHashMap(Biome.values().length);
public GeyserSpigotWorldManager(boolean use3dBiomes) {
this.use3dBiomes = use3dBiomes;
// Load the values into the biome-to-ID map
InputStream biomeStream = FileUtils.getResource("biomes.json");
JsonNode biomes;
try {
biomes = GeyserConnector.JSON_MAPPER.readTree(biomeStream);
} catch (Exception e) {
throw new AssertionError(LanguageUtils.getLocaleStringLog("geyser.toolbox.fail.runtime_java"), e);
}
// Only load in the biomes that are present in this version of Minecraft
for (Biome enumBiome : Biome.values()) {
JsonNode biome = biomes.get(enumBiome.toString());
if (biome != null) {
biomeToIdMap.put(enumBiome.ordinal(), biome.intValue());
} else {
GeyserConnector.getInstance().getLogger().debug("No biome mapping found for " + enumBiome.toString() +
", defaulting to 0");
biomeToIdMap.put(enumBiome.ordinal(), 0);
}
}
}
@Override
public int getBlockAt(GeyserSession session, int x, int y, int z) {
Player bukkitPlayer;
if ((bukkitPlayer = Bukkit.getPlayer(session.getPlayerEntity().getUsername())) == null) {
return BlockTranslator.JAVA_AIR_ID;
}
World world = bukkitPlayer.getWorld();
return BlockTranslator.getJavaIdBlockMap().getOrDefault(world.getBlockAt(x, y, z).getBlockData().getAsString(), BlockTranslator.JAVA_AIR_ID);
}
@Override
public void getBlocksInSection(GeyserSession session, int x, int y, int z, Chunk chunk) {
Player bukkitPlayer;
if ((bukkitPlayer = Bukkit.getPlayer(session.getPlayerEntity().getUsername())) == null) {
return;
}
World world = bukkitPlayer.getWorld();
for (int blockY = 0; blockY < 16; blockY++) { // Cache-friendly iteration order
for (int blockZ = 0; blockZ < 16; blockZ++) {
for (int blockX = 0; blockX < 16; blockX++) {
Block block = world.getBlockAt((x << 4) + blockX, (y << 4) + blockY, (z << 4) + blockZ);
int id = BlockTranslator.getJavaIdBlockMap().getOrDefault(block.getBlockData().getAsString(), BlockTranslator.JAVA_AIR_ID);
chunk.set(blockX, blockY, blockZ, id);
}
}
}
}
@Override
public boolean hasMoreBlockDataThanChunkCache() {
return true;
}
@Override
@SuppressWarnings("deprecation")
public int[] getBiomeDataAt(GeyserSession session, int x, int z) {
if (session.getPlayerEntity() == null) {
return new int[1024];
}
int[] biomeData = new int[1024];
World world = Bukkit.getPlayer(session.getPlayerEntity().getUsername()).getWorld();
int chunkX = x << 4;
int chunkZ = z << 4;
int chunkXmax = chunkX + 16;
int chunkZmax = chunkZ + 16;
// 3D biomes didn't exist until 1.15
if (use3dBiomes) {
for (int localX = chunkX; localX < chunkXmax; localX += 4) {
for (int localY = 0; localY < 255; localY += + 4) {
for (int localZ = chunkZ; localZ < chunkZmax; localZ += 4) {
// Index is based on wiki.vg's index requirements
final int i = ((localY >> 2) & 63) << 4 | ((localZ >> 2) & 3) << 2 | ((localX >> 2) & 3);
biomeData[i] = biomeToIdMap.getOrDefault(world.getBiome(localX, localY, localZ).ordinal(), 0);
}
}
}
} else {
// Looks like the same code, but we're not checking the Y coordinate here
for (int localX = chunkX; localX < chunkXmax; localX += 4) {
for (int localY = 0; localY < 255; localY += + 4) {
for (int localZ = chunkZ; localZ < chunkZmax; localZ += 4) {
// Index is based on wiki.vg's index requirements
final int i = ((localY >> 2) & 63) << 4 | ((localZ >> 2) & 3) << 2 | ((localX >> 2) & 3);
biomeData[i] = biomeToIdMap.getOrDefault(world.getBiome(localX, localZ).ordinal(), 0);
}
}
}
}
return biomeData;
}
public Boolean getGameRuleBool(GeyserSession session, GameRule gameRule) {
return Boolean.parseBoolean(Bukkit.getPlayer(session.getPlayerEntity().getUsername()).getWorld().getGameRuleValue(gameRule.getJavaID()));
}
@Override
public int getGameRuleInt(GeyserSession session, GameRule gameRule) {
return Integer.parseInt(Bukkit.getPlayer(session.getPlayerEntity().getUsername()).getWorld().getGameRuleValue(gameRule.getJavaID()));
}
@Override
public boolean hasPermission(GeyserSession session, String permission) {
return Bukkit.getPlayer(session.getPlayerEntity().getUsername()).hasPermission(permission);
}
/**
* This must be set to true if we are pre-1.13, and {@link BlockData#getAsString() does not exist}.
*
* This should be set to true if we are post-1.13 but before the latest version, and we should convert the old block state id
* to the current one.
*
* @return whether there is a difference between client block state and server block state that requires extra processing
*/
public boolean isLegacy() {
return false;
}
}

View File

@ -1,155 +0,0 @@
{
"MUTATED_ICE_FLATS" : 140,
"MUTATED_TAIGA" : 133,
"SAVANNA_PLATEAU_MOUNTAINS" : 164,
"DEEP_WARM_OCEAN" : 47,
"REDWOOD_TAIGA_HILLS" : 33,
"THE_VOID" : 127,
"COLD_TAIGA_MOUNTAINS" : 158,
"BAMBOO_JUNGLE_HILLS" : 169,
"MOUNTAINS" : 3,
"MESA_PLATEAU" : 39,
"SNOWY_TAIGA_HILLS" : 31,
"DEEP_FROZEN_OCEAN" : 50,
"EXTREME_HILLS" : 3,
"BIRCH_FOREST_MOUNTAINS" : 155,
"FOREST" : 4,
"BIRCH_FOREST" : 27,
"SNOWY_TUNDRA" : 12,
"ICE_SPIKES" : 140,
"FROZEN_OCEAN" : 10,
"WARPED_FOREST" : 172,
"WOODED_BADLANDS_PLATEAU" : 38,
"BADLANDS_PLATEAU" : 39,
"ICE_PLAINS_SPIKES" : 140,
"MEGA_TAIGA" : 32,
"MUTATED_SAVANNA_ROCK" : 164,
"SAVANNA_PLATEAU" : 36,
"DARK_FOREST_HILLS" : 157,
"END_MIDLANDS" : 41,
"SHATTERED_SAVANNA_PLATEAU" : 164,
"SAVANNA" : 35,
"MUSHROOM_ISLAND_SHORE" : 15,
"SWAMP" : 6,
"ICE_MOUNTAINS" : 13,
"BEACH" : 16,
"MUTATED_MESA_CLEAR_ROCK" : 167,
"END_HIGHLANDS" : 42,
"COLD_BEACH" : 26,
"JUNGLE" : 21,
"MUTATED_TAIGA_COLD" : 158,
"TALL_BIRCH_HILLS" : 156,
"DARK_FOREST" : 29,
"WOODED_HILLS" : 18,
"HELL" : 8,
"MUTATED_REDWOOD_TAIGA" : 160,
"MESA_PLATEAU_FOREST" : 38,
"MUSHROOM_ISLAND" : 14,
"BADLANDS" : 37,
"END_BARRENS" : 43,
"MUTATED_EXTREME_HILLS_WITH_TREES" : 162,
"MUTATED_JUNGLE_EDGE" : 151,
"MODIFIED_BADLANDS_PLATEAU" : 167,
"ROOFED_FOREST_MOUNTAINS" : 157,
"SOUL_SAND_VALLEY" : 170,
"DESERT" : 2,
"MUTATED_PLAINS" : 129,
"MUTATED_BIRCH_FOREST" : 155,
"WOODED_MOUNTAINS" : 34,
"TAIGA_HILLS" : 19,
"BAMBOO_JUNGLE" : 168,
"SWAMPLAND_MOUNTAINS" : 134,
"DESERT_MOUNTAINS" : 130,
"REDWOOD_TAIGA" : 32,
"MUSHROOM_FIELDS" : 14,
"GIANT_TREE_TAIGA_HILLS" : 33,
"PLAINS" : 1,
"JUNGLE_EDGE" : 23,
"SAVANNA_MOUNTAINS" : 163,
"DEEP_COLD_OCEAN" : 49,
"DESERT_LAKES" : 130,
"MOUNTAIN_EDGE" : 20,
"SNOWY_MOUNTAINS" : 13,
"MESA_PLATEAU_MOUNTAINS" : 167,
"JUNGLE_MOUNTAINS" : 149,
"SMALLER_EXTREME_HILLS" : 20,
"MESA_PLATEAU_FOREST_MOUNTAINS" : 166,
"NETHER_WASTES" : 8,
"BIRCH_FOREST_HILLS_MOUNTAINS" : 156,
"MUTATED_JUNGLE" : 149,
"WARM_OCEAN" : 44,
"DEEP_OCEAN" : 24,
"STONE_BEACH" : 25,
"MODIFIED_JUNGLE" : 149,
"MUTATED_SAVANNA" : 163,
"TAIGA_COLD_HILLS" : 31,
"OCEAN" : 0,
"SMALL_END_ISLANDS" : 40,
"MUSHROOM_FIELD_SHORE" : 15,
"GRAVELLY_MOUNTAINS" : 131,
"FROZEN_RIVER" : 11,
"TAIGA_COLD" : 30,
"BASALT_DELTAS" : 173,
"EXTREME_HILLS_WITH_TREES" : 34,
"MEGA_TAIGA_HILLS" : 33,
"MUTATED_FOREST" : 132,
"MUTATED_BIRCH_FOREST_HILLS" : 156,
"SKY" : 9,
"LUKEWARM_OCEAN" : 45,
"EXTREME_HILLS_MOUNTAINS" : 131,
"COLD_TAIGA_HILLS" : 31,
"THE_END" : 9,
"SUNFLOWER_PLAINS" : 129,
"SAVANNA_ROCK" : 36,
"ERODED_BADLANDS" : 165,
"STONE_SHORE" : 25,
"EXTREME_HILLS_PLUS_MOUNTAINS" : 162,
"CRIMSON_FOREST" : 171,
"VOID" : 127,
"SNOWY_TAIGA" : 30,
"SNOWY_TAIGA_MOUNTAINS" : 158,
"FLOWER_FOREST" : 132,
"COLD_OCEAN" : 46,
"BEACHES" : 16,
"MESA" : 37,
"MUSHROOM_SHORE" : 15,
"MESA_CLEAR_ROCK" : 39,
"NETHER" : 8,
"ICE_PLAINS" : 12,
"SHATTERED_SAVANNA" : 163,
"ROOFED_FOREST" : 29,
"GIANT_SPRUCE_TAIGA_HILLS" : 161,
"SNOWY_BEACH" : 26,
"MESA_BRYCE" : 165,
"JUNGLE_EDGE_MOUNTAINS" : 151,
"MUTATED_DESERT" : 130,
"MODIFIED_GRAVELLY_MOUNTAINS" : 158,
"MEGA_SPRUCE_TAIGA" : 160,
"TAIGA_MOUNTAINS" : 133,
"SMALL_MOUNTAINS" : 20,
"EXTREME_HILLS_PLUS" : 34,
"GIANT_SPRUCE_TAIGA" : 160,
"FOREST_HILLS" : 18,
"DESERT_HILLS" : 17,
"MUTATED_REDWOOD_TAIGA_HILLS" : 161,
"MEGA_SPRUCE_TAIGA_HILLS" : 161,
"RIVER" : 7,
"GIANT_TREE_TAIGA" : 32,
"SWAMPLAND" : 6,
"JUNGLE_HILLS" : 22,
"TALL_BIRCH_FOREST" : 155,
"DEEP_LUKEWARM_OCEAN" : 48,
"MESA_ROCK" : 38,
"SWAMP_HILLS" : 134,
"MODIFIED_WOODED_BADLANDS_PLATEAU" : 166,
"MODIFIED_JUNGLE_EDGE" : 151,
"BIRCH_FOREST_HILLS" : 28,
"COLD_TAIGA" : 30,
"TAIGA" : 5,
"MUTATED_MESA_ROCK" : 166,
"MUTATED_SWAMPLAND" : 134,
"ICE_FLATS" : 12,
"MUTATED_ROOFED_FOREST" : 157,
"MUTATED_MESA" : 165,
"MUTATED_EXTREME_HILLS" : 131
}

View File

@ -6,15 +6,15 @@
<parent>
<groupId>org.geysermc</groupId>
<artifactId>bootstrap-parent</artifactId>
<version>1.2.0-SNAPSHOT</version>
<version>1.0-SNAPSHOT</version>
<relativePath>../</relativePath>
</parent>
<artifactId>bootstrap-sponge</artifactId>
<dependencies>
<dependency>
<groupId>org.geysermc</groupId>
<artifactId>connector</artifactId>
<version>1.2.0-SNAPSHOT</version>
<version>1.0-SNAPSHOT</version>
<scope>compile</scope>
</dependency>
<dependency>
@ -69,26 +69,6 @@
<pattern>it.unimi.dsi.fastutil</pattern>
<shadedPattern>org.geysermc.platform.sponge.shaded.fastutil</shadedPattern>
</relocation>
<relocation>
<pattern>org.reflections</pattern>
<shadedPattern>org.geysermc.platform.sponge.shaded.reflections</shadedPattern>
</relocation>
<relocation>
<pattern>com.google.common</pattern>
<shadedPattern>org.geysermc.platform.sponge.shaded.google.common</shadedPattern>
</relocation>
<relocation>
<pattern>com.google.guava</pattern>
<shadedPattern>org.geysermc.platform.sponge.shaded.google.guava</shadedPattern>
</relocation>
<relocation>
<pattern>org.dom4j</pattern>
<shadedPattern>org.geysermc.platform.sponge.shaded.dom4j</shadedPattern>
</relocation>
<relocation>
<pattern>net.kyori</pattern>
<shadedPattern>org.geysermc.platform.sponge.shaded.kyori</shadedPattern>
</relocation>
</relocations>
</configuration>
</execution>

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2019-2021 GeyserMC. http://geysermc.org
* Copyright (c) 2019-2020 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
@ -25,13 +25,216 @@
package org.geysermc.platform.sponge;
import org.geysermc.connector.configuration.GeyserJacksonConfiguration;
import lombok.AllArgsConstructor;
import ninja.leaping.configurate.ConfigurationNode;
import org.geysermc.connector.GeyserConfiguration;
import java.io.File;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.*;
public class GeyserSpongeConfiguration implements GeyserConfiguration {
private File dataFolder;
private ConfigurationNode node;
private SpongeBedrockConfiguration bedrockConfig;
private SpongeRemoteConfiguration remoteConfig;
private SpongeMetricsInfo metricsInfo;
private Map<String, SpongeUserAuthenticationInfo> userAuthInfo = new HashMap<>();
public GeyserSpongeConfiguration(File dataFolder, ConfigurationNode node) {
this.dataFolder = dataFolder;
this.node = node;
this.bedrockConfig = new SpongeBedrockConfiguration(node.getNode("bedrock"));
this.remoteConfig = new SpongeRemoteConfiguration(node.getNode("remote"));
this.metricsInfo = new SpongeMetricsInfo();
if (node.getNode("userAuths").getValue() == null)
return;
List<String> userAuths = new ArrayList<String>(((LinkedHashMap)node.getNode("userAuths").getValue()).keySet());
for (String key : userAuths) {
userAuthInfo.put(key, new SpongeUserAuthenticationInfo(key));
}
}
public final class GeyserSpongeConfiguration extends GeyserJacksonConfiguration {
@Override
public Path getFloodgateKeyPath() {
return null; //floodgate isn't available for Sponge
public SpongeBedrockConfiguration getBedrock() {
return bedrockConfig;
}
@Override
public SpongeRemoteConfiguration getRemote() {
return remoteConfig;
}
@Override
public Map<String, SpongeUserAuthenticationInfo> getUserAuths() {
return userAuthInfo;
}
@Override
public boolean isCommandSuggestions() {
return node.getNode("command-suggestions").getBoolean(true);
}
@Override
public boolean isPassthroughMotd() {
return node.getNode("passthrough-motd").getBoolean(false);
}
@Override
public boolean isPassthroughPlayerCounts() {
return node.getNode("passthrough-player-counts").getBoolean(false);
}
@Override
public boolean isLegacyPingPassthrough() {
return node.getNode("legacy-ping-passthrough").getBoolean(false);
}
@Override
public int getPingPassthroughInterval() {
return node.getNode("ping-passthrough-interval").getInt(3);
}
@Override
public int getMaxPlayers() {
return node.getNode("max-players").getInt(100);
}
@Override
public boolean isDebugMode() {
return node.getNode("debug-mode").getBoolean(false);
}
@Override
public int getGeneralThreadPool() {
return node.getNode("genereal-thread-pool").getInt(32);
}
@Override
public boolean isAllowThirdPartyCapes() {
return node.getNode("allow-third-party-capes").getBoolean(true);
}
@Override
public boolean isAllowThirdPartyEars() {
return node.getNode("allow-third-party-ears").getBoolean(false);
}
@Override
public String getDefaultLocale() {
return node.getNode("default-locale").getString("en_us");
}
@Override
public Path getFloodgateKeyFile() {
return Paths.get(dataFolder.toString(), node.getNode("floodgate-key-file").getString("public-key.pem"));
}
@Override
public boolean isCacheChunks() {
return node.getNode("cache-chunks").getBoolean(false);
}
@Override
public boolean isAboveBedrockNetherBuilding() {
return node.getNode("above-bedrock-nether-building").getBoolean(false);
}
@Override
public SpongeMetricsInfo getMetrics() {
return metricsInfo;
}
@AllArgsConstructor
public class SpongeBedrockConfiguration implements IBedrockConfiguration {
private ConfigurationNode node;
@Override
public String getAddress() {
return node.getNode("address").getString("0.0.0.0");
}
@Override
public int getPort() {
return node.getNode("port").getInt(19132);
}
@Override
public String getMotd1() {
return node.getNode("motd1").getString("GeyserMC");
}
@Override
public String getMotd2() {
return node.getNode("motd2").getString("GeyserMC");
}
}
@AllArgsConstructor
public class SpongeRemoteConfiguration implements IRemoteConfiguration {
private ConfigurationNode node;
@Override
public String getAddress() {
return node.getNode("address").getString("127.0.0.1");
}
@Override
public int getPort() {
return node.getNode("port").getInt(25565);
}
@Override
public String getAuthType() {
return node.getNode("auth-type").getString("online");
}
}
public class SpongeUserAuthenticationInfo implements IUserAuthenticationInfo {
private String key;
public SpongeUserAuthenticationInfo(String key) {
this.key = key;
}
@Override
public String getEmail() {
return node.getNode("userAuths").getNode(key).getNode("email").getString();
}
@Override
public String getPassword() {
return node.getNode("userAuths").getNode(key).getNode("password").getString();
}
}
public class SpongeMetricsInfo implements IMetricsInfo {
@Override
public boolean isEnabled() {
return node.getNode("metrics").getNode("enabled").getBoolean(true);
}
@Override
public String getUniqueId() {
return node.getNode("metrics").getNode("uuid").getString("generateduuid");
}
}
@Override
public int getConfigVersion() {
return node.getNode("config-version").getInt(0);
}
}

View File

@ -1,62 +0,0 @@
/*
* Copyright (c) 2019-2021 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/Geyser
*/
package org.geysermc.platform.sponge;
import lombok.Getter;
import org.geysermc.connector.dump.BootstrapDumpInfo;
import org.spongepowered.api.Platform;
import org.spongepowered.api.Sponge;
import org.spongepowered.api.plugin.PluginContainer;
import java.util.ArrayList;
import java.util.List;
@Getter
public class GeyserSpongeDumpInfo extends BootstrapDumpInfo {
private String platformName;
private String platformVersion;
private boolean onlineMode;
private String serverIP;
private int serverPort;
private List<PluginInfo> plugins;
GeyserSpongeDumpInfo() {
super();
PluginContainer container = Sponge.getPlatform().getContainer(Platform.Component.IMPLEMENTATION);
this.platformName = container.getName();
this.platformVersion = container.getVersion().get();
this.onlineMode = Sponge.getServer().getOnlineMode();
this.serverIP = Sponge.getServer().getBoundAddress().get().getHostString();
this.serverPort = Sponge.getServer().getBoundAddress().get().getPort();
this.plugins = new ArrayList<>();
for (PluginContainer plugin : Sponge.getPluginManager().getPlugins()) {
String pluginClass = plugin.getInstance().map((pl) -> pl.getClass().getName()).orElse("unknown");
this.plugins.add(new PluginInfo(true, plugin.getName(), plugin.getVersion().get(), pluginClass, plugin.getAuthors()));
}
}
}

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2019-2021 GeyserMC. http://geysermc.org
* Copyright (c) 2019-2020 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
@ -26,16 +26,15 @@
package org.geysermc.platform.sponge;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.Setter;
import org.geysermc.connector.GeyserLogger;
import org.slf4j.Logger;
@AllArgsConstructor
public class GeyserSpongeLogger implements GeyserLogger {
private final Logger logger;
@Getter @Setter
private boolean debug;
private Logger logger;
private boolean debugMode;
@Override
public void severe(String message) {
@ -69,8 +68,12 @@ public class GeyserSpongeLogger implements GeyserLogger {
@Override
public void debug(String message) {
if (debug) {
if (debugMode)
info(message);
}
}
@Override
public void setDebug(boolean debugMode) {
this.debugMode = debugMode;
}
}

View File

@ -1,31 +1,32 @@
/*
* Copyright (c) 2019-2021 GeyserMC. http://geysermc.org
* Copyright (c) 2019-2020 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:
* 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 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.
* 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/Geyser
*
* @author GeyserMC
* @link https://github.com/GeyserMC/Geyser
*/
package org.geysermc.platform.sponge;
import org.geysermc.connector.common.main.IGeyserMain;
import org.geysermc.common.main.IGeyserMain;
public class GeyserSpongeMain extends IGeyserMain {

View File

@ -1,32 +1,32 @@
/*
* Copyright (c) 2019-2021 GeyserMC. http://geysermc.org
* Copyright (c) 2019-2020 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:
* 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 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.
* 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/Geyser
*
* @author GeyserMC
* @link https://github.com/GeyserMC/Geyser
*/
package org.geysermc.platform.sponge;
import com.github.steveice10.mc.protocol.MinecraftConstants;
import org.geysermc.connector.common.ping.GeyserPingInfo;
import org.geysermc.common.ping.GeyserPingInfo;
import org.geysermc.connector.ping.IGeyserPingPassthrough;
import org.spongepowered.api.MinecraftVersion;
import org.spongepowered.api.Sponge;
@ -35,65 +35,55 @@ import org.spongepowered.api.event.cause.Cause;
import org.spongepowered.api.event.cause.EventContext;
import org.spongepowered.api.event.server.ClientPingServerEvent;
import org.spongepowered.api.network.status.StatusClient;
import org.spongepowered.api.profile.GameProfile;
import java.lang.reflect.Method;
import java.net.Inet4Address;
import java.net.InetSocketAddress;
import java.util.Optional;
public class GeyserSpongePingPassthrough implements IGeyserPingPassthrough {
private static final GeyserStatusClient STATUS_CLIENT = new GeyserStatusClient();
private static final Cause CAUSE = Cause.of(EventContext.empty(), Sponge.getServer());
private static Method SpongeStatusResponse_create;
@SuppressWarnings({"unchecked", "rawtypes"})
@Override
public GeyserPingInfo getPingInformation(InetSocketAddress inetSocketAddress) {
public GeyserPingInfo getPingInformation() {
// come on Sponge, this is in commons, why not expose it :(
ClientPingServerEvent event;
try {
if (SpongeStatusResponse_create == null) {
if(SpongeStatusResponse_create == null) {
Class SpongeStatusResponse = Class.forName("org.spongepowered.common.network.status.SpongeStatusResponse");
Class MinecraftServer = Class.forName("net.minecraft.server.MinecraftServer");
SpongeStatusResponse_create = SpongeStatusResponse.getDeclaredMethod("create", MinecraftServer);
}
Object response = SpongeStatusResponse_create.invoke(null, Sponge.getServer());
event = SpongeEventFactory.createClientPingServerEvent(CAUSE, new GeyserStatusClient(inetSocketAddress), (ClientPingServerEvent.Response) response);
event = SpongeEventFactory.createClientPingServerEvent(CAUSE, STATUS_CLIENT, (ClientPingServerEvent.Response) response);
} catch (ReflectiveOperationException e) {
throw new RuntimeException(e);
}
Sponge.getEventManager().post(event);
GeyserPingInfo geyserPingInfo = new GeyserPingInfo(
event.getResponse().getDescription().toPlain(),
new GeyserPingInfo.Players(
event.getResponse().getPlayers().orElseThrow(IllegalStateException::new).getMax(),
event.getResponse().getPlayers().orElseThrow(IllegalStateException::new).getOnline()
),
new GeyserPingInfo.Version(
event.getResponse().getVersion().getName(),
MinecraftConstants.PROTOCOL_VERSION) // thanks for also not exposing this sponge
);
event.getResponse().getPlayers().get().getProfiles().stream()
.map(GameProfile::getName)
.map(op -> op.orElseThrow(IllegalStateException::new))
.forEach(geyserPingInfo.getPlayerList()::add);
event.getResponse().getPlayers().orElseThrow(IllegalStateException::new).getOnline(),
event.getResponse().getPlayers().orElseThrow(IllegalStateException::new).getMax());
event.getResponse().getPlayers().get().getProfiles().forEach(player -> {
geyserPingInfo.addPlayer(player.getName().orElseThrow(IllegalStateException::new));
});
return geyserPingInfo;
}
@SuppressWarnings("NullableProblems")
private static class GeyserStatusClient implements StatusClient {
private final InetSocketAddress remote;
public GeyserStatusClient(InetSocketAddress remote) {
this.remote = remote;
}
private static final InetSocketAddress FAKE_REMOTE = new InetSocketAddress(Inet4Address.getLoopbackAddress(), 69);
@Override
public InetSocketAddress getAddress() {
return this.remote;
return FAKE_REMOTE;
}
@Override

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2019-2021 GeyserMC. http://geysermc.org
* Copyright (c) 2019-2020 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
@ -26,16 +26,17 @@
package org.geysermc.platform.sponge;
import com.google.inject.Inject;
import ninja.leaping.configurate.ConfigurationNode;
import ninja.leaping.configurate.loader.ConfigurationLoader;
import ninja.leaping.configurate.yaml.YAMLConfigurationLoader;
import org.geysermc.common.PlatformType;
import org.geysermc.connector.GeyserConfiguration;
import org.geysermc.connector.GeyserConnector;
import org.geysermc.connector.bootstrap.GeyserBootstrap;
import org.geysermc.connector.command.CommandManager;
import org.geysermc.connector.configuration.GeyserConfiguration;
import org.geysermc.connector.dump.BootstrapDumpInfo;
import org.geysermc.connector.ping.GeyserLegacyPingPassthrough;
import org.geysermc.connector.ping.IGeyserPingPassthrough;
import org.geysermc.connector.utils.FileUtils;
import org.geysermc.connector.utils.LanguageUtils;
import org.geysermc.platform.sponge.command.GeyserSpongeCommandExecutor;
import org.geysermc.platform.sponge.command.GeyserSpongeCommandManager;
import org.slf4j.Logger;
@ -49,7 +50,6 @@ import org.spongepowered.api.plugin.Plugin;
import java.io.File;
import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.file.Path;
import java.util.UUID;
@Plugin(id = "geyser", name = GeyserConnector.NAME + "-Sponge", version = GeyserConnector.VERSION, url = "https://geysermc.org", authors = "GeyserMC")
@ -78,31 +78,34 @@ public class GeyserSpongePlugin implements GeyserBootstrap {
try {
configFile = FileUtils.fileOrCopiedFromResource(new File(configDir, "config.yml"), "config.yml", (file) -> file.replaceAll("generateduuid", UUID.randomUUID().toString()));
} catch (IOException ex) {
logger.warn(LanguageUtils.getLocaleStringLog("geyser.config.failed"));
logger.warn("Failed to copy config.yml from jar path!");
ex.printStackTrace();
}
ConfigurationLoader loader = YAMLConfigurationLoader.builder().setPath(configFile.toPath()).build();
ConfigurationNode config;
try {
this.geyserConfig = FileUtils.loadConfig(configFile, GeyserSpongeConfiguration.class);
config = loader.load();
this.geyserConfig = new GeyserSpongeConfiguration(configDir, config);
} catch (IOException ex) {
logger.warn(LanguageUtils.getLocaleStringLog("geyser.config.failed"));
logger.warn("Failed to load config.yml!");
ex.printStackTrace();
return;
}
ConfigurationNode serverIP = config.getNode("remote").getNode("address");
ConfigurationNode serverPort = config.getNode("remote").getNode("port");
if (Sponge.getServer().getBoundAddress().isPresent()) {
InetSocketAddress javaAddr = Sponge.getServer().getBoundAddress().get();
// Don't change the ip if its listening on all interfaces
// By default this should be 127.0.0.1 but may need to be changed in some circumstances
if (this.geyserConfig.getRemote().getAddress().equalsIgnoreCase("auto")) {
this.geyserConfig.setAutoconfiguredRemote(true);
geyserConfig.getRemote().setPort(javaAddr.getPort());
if (!javaAddr.getHostString().equals("0.0.0.0") && !javaAddr.getHostString().equals("")) {
serverIP.setValue("127.0.0.1");
}
}
if (geyserConfig.getBedrock().isCloneRemotePort()){
geyserConfig.getBedrock().setPort(geyserConfig.getRemote().getPort());
serverPort.setValue(javaAddr.getPort());
}
this.geyserLogger = new GeyserSpongeLogger(logger, geyserConfig.isDebugMode());
@ -144,11 +147,6 @@ public class GeyserSpongePlugin implements GeyserBootstrap {
return geyserSpongePingPassthrough;
}
@Override
public Path getConfigFolder() {
return configDir.toPath();
}
@Listener
public void onServerStart(GameStartedServerEvent event) {
onEnable();
@ -158,9 +156,4 @@ public class GeyserSpongePlugin implements GeyserBootstrap {
public void onServerStop(GameStoppedEvent event) {
onDisable();
}
@Override
public BootstrapDumpInfo getDumpInfo() {
return new GeyserSpongeDumpInfo();
}
}

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2019-2021 GeyserMC. http://geysermc.org
* Copyright (c) 2019-2020 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
@ -26,10 +26,10 @@
package org.geysermc.platform.sponge.command;
import lombok.AllArgsConstructor;
import org.geysermc.common.ChatColor;
import org.geysermc.connector.GeyserConnector;
import org.geysermc.connector.common.ChatColor;
import org.geysermc.connector.command.GeyserCommand;
import org.geysermc.connector.utils.LanguageUtils;
import org.spongepowered.api.command.CommandCallable;
import org.spongepowered.api.command.CommandException;
import org.spongepowered.api.command.CommandResult;
@ -55,14 +55,13 @@ public class GeyserSpongeCommandExecutor implements CommandCallable {
if (args.length > 0) {
if (getCommand(args[0]) != null) {
if (!source.hasPermission(getCommand(args[0]).getPermission())) {
// Not ideal to use log here but we dont get a session
source.sendMessage(Text.of(ChatColor.RED + LanguageUtils.getLocaleStringLog("geyser.bootstrap.command.permission_fail")));
source.sendMessage(Text.of(ChatColor.RED + "You do not have permission to execute this command!"));
return CommandResult.success();
}
getCommand(args[0]).execute(new SpongeCommandSender(source), args.length > 1 ? Arrays.copyOfRange(args, 1, args.length) : new String[0]);
getCommand(args[0]).execute(new SpongeCommandSender(source), args);
}
} else {
getCommand("help").execute(new SpongeCommandSender(source), new String[0]);
getCommand("help").execute(new SpongeCommandSender(source), args);
}
return CommandResult.success();
}
@ -70,7 +69,7 @@ public class GeyserSpongeCommandExecutor implements CommandCallable {
@Override
public List<String> getSuggestions(CommandSource source, String arguments, @Nullable Location<World> targetPosition) throws CommandException {
if (arguments.split(" ").length == 1) {
return connector.getCommandManager().getCommandNames();
return Arrays.asList("?", "help", "reload", "shutdown", "stop");
}
return new ArrayList<>();
}

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2019-2021 GeyserMC. http://geysermc.org
* Copyright (c) 2019-2020 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

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2019-2021 GeyserMC. http://geysermc.org
* Copyright (c) 2019-2020 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

View File

@ -6,21 +6,21 @@
<parent>
<groupId>org.geysermc</groupId>
<artifactId>bootstrap-parent</artifactId>
<version>1.2.0-SNAPSHOT</version>
<version>1.0-SNAPSHOT</version>
<relativePath>../</relativePath>
</parent>
<artifactId>bootstrap-standalone</artifactId>
<dependencies>
<dependency>
<groupId>org.geysermc</groupId>
<artifactId>connector</artifactId>
<version>1.2.0-SNAPSHOT</version>
<version>1.0-SNAPSHOT</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>net.minecrell</groupId>
<artifactId>terminalconsoleappender</artifactId>
<version>1.2.0</version>
<version>1.1.1</version>
<exclusions>
<exclusion>
<groupId>org.apache.logging.log4j</groupId>
@ -63,7 +63,7 @@
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-core</artifactId>
<version>2.13.2</version>
<version>2.13.1</version>
</dependency>
<dependency>
<groupId>org.apache.logging.log4j</groupId>

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2019-2021 GeyserMC. http://geysermc.org
* Copyright (c) 2019-2020 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
@ -25,39 +25,19 @@
package org.geysermc.platform.standalone;
import com.fasterxml.jackson.databind.BeanDescription;
import com.fasterxml.jackson.databind.JavaType;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.introspect.AnnotatedField;
import com.fasterxml.jackson.databind.introspect.BeanPropertyDefinition;
import lombok.Getter;
import net.minecrell.terminalconsole.TerminalConsoleAppender;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.core.Appender;
import org.apache.logging.log4j.core.Logger;
import org.apache.logging.log4j.core.appender.ConsoleAppender;
import org.geysermc.common.PlatformType;
import org.geysermc.connector.GeyserConnector;
import org.geysermc.connector.bootstrap.GeyserBootstrap;
import org.geysermc.connector.command.CommandManager;
import org.geysermc.connector.configuration.GeyserConfiguration;
import org.geysermc.connector.configuration.GeyserJacksonConfiguration;
import org.geysermc.connector.dump.BootstrapDumpInfo;
import org.geysermc.connector.ping.GeyserLegacyPingPassthrough;
import org.geysermc.connector.GeyserConfiguration;
import org.geysermc.connector.bootstrap.GeyserBootstrap;
import org.geysermc.connector.GeyserConnector;
import org.geysermc.connector.command.CommandManager;
import org.geysermc.connector.ping.IGeyserPingPassthrough;
import org.geysermc.connector.utils.FileUtils;
import org.geysermc.connector.utils.LanguageUtils;
import org.geysermc.platform.standalone.command.GeyserCommandManager;
import org.geysermc.platform.standalone.gui.GeyserStandaloneGUI;
import java.io.File;
import java.io.IOException;
import java.lang.reflect.Method;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.text.MessageFormat;
import java.util.*;
import java.util.stream.Collectors;
import java.util.UUID;
public class GeyserStandaloneBootstrap implements GeyserBootstrap {
@ -66,180 +46,33 @@ public class GeyserStandaloneBootstrap implements GeyserBootstrap {
private GeyserStandaloneLogger geyserLogger;
private IGeyserPingPassthrough geyserPingPassthrough;
private GeyserStandaloneGUI gui;
@Getter
private boolean useGui = System.console() == null && !isHeadless();
private String configFilename = "config.yml";
private GeyserConnector connector;
private static final ObjectMapper OBJECT_MAPPER = new ObjectMapper();
private static final Map<String, String> argsConfigKeys = new HashMap<>();
public static void main(String[] args) {
GeyserStandaloneBootstrap bootstrap = new GeyserStandaloneBootstrap();
// Set defaults
boolean useGuiOpts = bootstrap.useGui;
String configFilenameOpt = bootstrap.configFilename;
List<BeanPropertyDefinition> availableProperties = getPOJOForClass(GeyserJacksonConfiguration.class);
for (int i = 0; i < args.length; i++) {
// By default, standalone Geyser will check if it should open the GUI based on if the GUI is null
// Optionally, you can force the use of a GUI or no GUI by specifying args
// Allows gui and nogui without options, for backwards compatibility
String arg = args[i];
switch (arg) {
case "--gui":
case "gui":
useGuiOpts = true;
break;
case "--nogui":
case "nogui":
useGuiOpts = false;
break;
case "--config":
case "-c":
if (i >= args.length - 1) {
System.err.println(MessageFormat.format(LanguageUtils.getLocaleStringLog("geyser.bootstrap.args.config_not_specified"), "-c"));
return;
}
configFilenameOpt = args[i+1]; i++;
System.out.println(MessageFormat.format(LanguageUtils.getLocaleStringLog("geyser.bootstrap.args.config_specified"), configFilenameOpt));
break;
case "--help":
case "-h":
System.out.println(MessageFormat.format(LanguageUtils.getLocaleStringLog("geyser.bootstrap.args.usage"), "[java -jar] Geyser.jar [opts]"));
System.out.println(" " + LanguageUtils.getLocaleStringLog("geyser.bootstrap.args.options"));
System.out.println(" -c, --config [file] " + LanguageUtils.getLocaleStringLog("geyser.bootstrap.args.config"));
System.out.println(" -h, --help " + LanguageUtils.getLocaleStringLog("geyser.bootstrap.args.help"));
System.out.println(" --gui, --nogui " + LanguageUtils.getLocaleStringLog("geyser.bootstrap.args.gui"));
return;
default:
// We have likely added a config option argument
if (arg.startsWith("--")) {
// Split the argument by an =
String[] argParts = arg.substring(2).split("=");
if (argParts.length == 2) {
// Split the config key by . to allow for nested options
String[] configKeyParts = argParts[0].split("\\.");
// Loop the possible config options to check the passed key is valid
boolean found = false;
for (BeanPropertyDefinition property : availableProperties) {
if (configKeyParts[0].equals(property.getName())) {
if (configKeyParts.length > 1) {
// Loop sub-section options to check the passed key is valid
for (BeanPropertyDefinition subProperty : getPOJOForClass(property.getRawPrimaryType())) {
if (configKeyParts[1].equals(subProperty.getName())) {
found = true;
break;
}
}
} else {
found = true;
}
break;
}
}
// Add the found key to the stored list for later usage
if (found) {
argsConfigKeys.put(argParts[0], argParts[1]);
break;
}
}
}
System.err.println(LanguageUtils.getLocaleStringLog("geyser.bootstrap.args.unrecognised", arg));
return;
}
}
bootstrap.onEnable(useGuiOpts, configFilenameOpt);
}
public void onEnable(boolean useGui, String configFilename) {
this.configFilename = configFilename;
this.useGui = useGui;
this.onEnable();
}
public void onEnable(boolean useGui) {
this.useGui = useGui;
this.onEnable();
new GeyserStandaloneBootstrap().onEnable();
}
@Override
public void onEnable() {
Logger logger = (Logger) LogManager.getRootLogger();
for (Appender appender : logger.getAppenders().values()) {
// Remove the appender that is not in use
// Prevents multiple appenders/double logging and removes harmless errors
if ((useGui && appender instanceof TerminalConsoleAppender) || (!useGui && appender instanceof ConsoleAppender)) {
logger.removeAppender(appender);
}
}
if (useGui && gui == null) {
gui = new GeyserStandaloneGUI();
gui.redirectSystemStreams();
gui.startUpdateThread();
}
geyserLogger = new GeyserStandaloneLogger();
LoopbackUtil.checkLoopback(geyserLogger);
try {
File configFile = FileUtils.fileOrCopiedFromResource(new File(configFilename), "config.yml", (x) -> x.replaceAll("generateduuid", UUID.randomUUID().toString()));
File configFile = FileUtils.fileOrCopiedFromResource("config.yml", (x) -> x.replaceAll("generateduuid", UUID.randomUUID().toString()));
geyserConfig = FileUtils.loadConfig(configFile, GeyserStandaloneConfiguration.class);
handleArgsConfigOptions();
if (this.geyserConfig.getRemote().getAddress().equalsIgnoreCase("auto")) {
geyserConfig.setAutoconfiguredRemote(true); // Doesn't really need to be set but /shrug
geyserConfig.getRemote().setAddress("127.0.0.1");
}
} catch (IOException ex) {
geyserLogger.severe(LanguageUtils.getLocaleStringLog("geyser.config.failed"), ex);
if (gui == null) {
System.exit(1);
} else {
// Leave the process running so the GUI is still visible
return;
}
geyserLogger.severe("Failed to read/create config.yml! Make sure it's up to date and/or readable+writable!", ex);
System.exit(0);
}
GeyserConfiguration.checkGeyserConfiguration(geyserConfig, geyserLogger);
connector = GeyserConnector.start(PlatformType.STANDALONE, this);
geyserCommandManager = new GeyserCommandManager(connector);
if (gui != null) {
gui.setupInterface(geyserLogger, geyserCommandManager);
}
geyserPingPassthrough = GeyserLegacyPingPassthrough.init(connector);
if (!useGui) {
geyserLogger.start(); // Throws an error otherwise
}
}
/**
* Check using {@link java.awt.GraphicsEnvironment} that we are a headless client
*
* @return If the current environment is headless
*/
private boolean isHeadless() {
try {
Class<?> graphicsEnv = Class.forName("java.awt.GraphicsEnvironment");
Method isHeadless = graphicsEnv.getDeclaredMethod("isHeadless");
return (boolean) isHeadless.invoke(null);
} catch (Exception ignore) { }
return true;
geyserLogger.start();
}
@Override
@ -267,110 +100,4 @@ public class GeyserStandaloneBootstrap implements GeyserBootstrap {
public IGeyserPingPassthrough getGeyserPingPassthrough() {
return geyserPingPassthrough;
}
@Override
public Path getConfigFolder() {
// Return the current working directory
return Paths.get(System.getProperty("user.dir"));
}
@Override
public BootstrapDumpInfo getDumpInfo() {
return new GeyserStandaloneDumpInfo(this);
}
/**
* Get the {@link BeanPropertyDefinition}s for the given class
*
* @param clazz The class to get the definitions for
* @return A list of {@link BeanPropertyDefinition} for the given class
*/
public static List<BeanPropertyDefinition> getPOJOForClass(Class<?> clazz) {
JavaType javaType = OBJECT_MAPPER.getTypeFactory().constructType(clazz);
// Introspect the given type
BeanDescription beanDescription = OBJECT_MAPPER.getSerializationConfig().introspect(javaType);
// Find properties
List<BeanPropertyDefinition> properties = beanDescription.findProperties();
// Get the ignored properties
Set<String> ignoredProperties = OBJECT_MAPPER.getSerializationConfig().getAnnotationIntrospector()
.findPropertyIgnorals(beanDescription.getClassInfo()).getIgnored();
// Filter properties removing the ignored ones
return properties.stream()
.filter(property -> !ignoredProperties.contains(property.getName()))
.collect(Collectors.toList());
}
/**
* Set a POJO property value on an object
*
* @param property The {@link BeanPropertyDefinition} to set
* @param parentObject The object to alter
* @param value The new value of the property
*/
private static void setConfigOption(BeanPropertyDefinition property, Object parentObject, Object value) {
Object parsedValue = value;
// Change the values type if needed
if (int.class.equals(property.getRawPrimaryType())) {
parsedValue = Integer.valueOf((String) parsedValue);
} else if (boolean.class.equals(property.getRawPrimaryType())) {
parsedValue = Boolean.valueOf((String) parsedValue);
}
// Force the value to be set
AnnotatedField field = property.getField();
field.fixAccess(true);
field.setValue(parentObject, parsedValue);
}
/**
* Update the loaded {@link GeyserStandaloneConfiguration} with any values passed in the command line arguments
*/
private void handleArgsConfigOptions() {
// Get the available properties from the class
List<BeanPropertyDefinition> availableProperties = getPOJOForClass(GeyserJacksonConfiguration.class);
for (Map.Entry<String, String> configKey : argsConfigKeys.entrySet()) {
String[] configKeyParts = configKey.getKey().split("\\.");
// Loop over the properties looking for any matches against the stored one from the argument
for (BeanPropertyDefinition property : availableProperties) {
if (configKeyParts[0].equals(property.getName())) {
if (configKeyParts.length > 1) {
// Loop through the sub property if the first part matches
for (BeanPropertyDefinition subProperty : getPOJOForClass(property.getRawPrimaryType())) {
if (configKeyParts[1].equals(subProperty.getName())) {
geyserLogger.info(LanguageUtils.getLocaleStringLog("geyser.bootstrap.args.set_config_option", configKey.getKey(), configKey.getValue()));
// Set the sub property value on the config
try {
Object subConfig = property.getGetter().callOn(geyserConfig);
setConfigOption(subProperty, subConfig, configKey.getValue());
} catch (Exception e) {
geyserLogger.error("Failed to set config option: " + property.getFullName());
}
break;
}
}
} else {
geyserLogger.info(LanguageUtils.getLocaleStringLog("geyser.bootstrap.args.set_config_option", configKey.getKey(), configKey.getValue()));
// Set the property value on the config
try {
setConfigOption(property, geyserConfig, configKey.getValue());
} catch (Exception e) {
geyserLogger.error("Failed to set config option: " + property.getFullName());
}
}
break;
}
}
}
}
}

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2019-2021 GeyserMC. http://geysermc.org
* Copyright (c) 2019-2020 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
@ -26,17 +26,111 @@
package org.geysermc.platform.standalone;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.fasterxml.jackson.annotation.JsonProperty;
import lombok.Getter;
import org.geysermc.connector.configuration.GeyserJacksonConfiguration;
import org.geysermc.connector.GeyserConfiguration;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.Map;
@Getter
@JsonIgnoreProperties(ignoreUnknown = true)
public final class GeyserStandaloneConfiguration extends GeyserJacksonConfiguration {
@Getter
public class GeyserStandaloneConfiguration implements GeyserConfiguration {
private BedrockConfiguration bedrock;
private RemoteConfiguration remote;
@JsonProperty("floodgate-key-file")
private String floodgateKeyFile;
private Map<String, UserAuthenticationInfo> userAuths;
@JsonProperty("command-suggestions")
private boolean isCommandSuggestions;
@JsonProperty("passthrough-motd")
private boolean isPassthroughMotd;
@JsonProperty("passthrough-player-counts")
private boolean isPassthroughPlayerCounts;
@JsonProperty("legacy-ping-passthrough")
private boolean isLegacyPingPassthrough;
@JsonProperty("ping-passthrough-interval")
private int pingPassthroughInterval;
@JsonProperty("max-players")
private int maxPlayers;
@JsonProperty("debug-mode")
private boolean debugMode;
@JsonProperty("general-thread-pool")
private int generalThreadPool;
@JsonProperty("allow-third-party-capes")
private boolean allowThirdPartyCapes;
@JsonProperty("allow-third-party-ears")
private boolean allowThirdPartyEars;
@JsonProperty("default-locale")
private String defaultLocale;
@JsonProperty("cache-chunks")
private boolean cacheChunks;
@JsonProperty("above-bedrock-nether-building")
private boolean isAboveBedrockNetherBuilding;
private MetricsInfo metrics;
@Override
public Path getFloodgateKeyPath() {
return Paths.get(getFloodgateKeyFile());
public Path getFloodgateKeyFile() {
return Paths.get(floodgateKeyFile);
}
@Getter
public static class BedrockConfiguration implements IBedrockConfiguration {
private String address;
private int port;
private String motd1;
private String motd2;
}
@Getter
public static class RemoteConfiguration implements IRemoteConfiguration {
private String address;
private int port;
private String motd1;
private String motd2;
@JsonProperty("auth-type")
private String authType;
}
@Getter
public static class UserAuthenticationInfo implements IUserAuthenticationInfo {
private String email;
private String password;
}
@Getter
public static class MetricsInfo implements IMetricsInfo {
private boolean enabled;
@JsonProperty("uuid")
private String uniqueId;
}
@JsonProperty("config-version")
private int configVersion;
}

View File

@ -1,40 +0,0 @@
/*
* Copyright (c) 2019-2021 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/Geyser
*/
package org.geysermc.platform.standalone;
import lombok.Getter;
import org.geysermc.connector.dump.BootstrapDumpInfo;
@Getter
public class GeyserStandaloneDumpInfo extends BootstrapDumpInfo {
private boolean isGui;
GeyserStandaloneDumpInfo(GeyserStandaloneBootstrap bootstrap) {
super();
this.isGui = bootstrap.isUseGui();
}
}

View File

@ -1,41 +1,43 @@
/*
* Copyright (c) 2019-2021 GeyserMC. http://geysermc.org
* Copyright (c) 2019-2020 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:
* 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 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.
* 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/Geyser
*
* @author GeyserMC
* @link https://github.com/GeyserMC/Geyser
*/
package org.geysermc.platform.standalone;
import lombok.extern.log4j.Log4j2;
import net.minecrell.terminalconsole.SimpleTerminalConsole;
import org.apache.logging.log4j.Level;
import org.apache.logging.log4j.core.config.Configurator;
import org.geysermc.common.ChatColor;
import org.geysermc.connector.GeyserConnector;
import org.geysermc.connector.GeyserLogger;
import org.geysermc.connector.command.CommandSender;
import org.geysermc.connector.common.ChatColor;
@Log4j2
public class GeyserStandaloneLogger extends SimpleTerminalConsole implements GeyserLogger, CommandSender {
public class GeyserStandaloneLogger extends SimpleTerminalConsole implements org.geysermc.connector.GeyserLogger, CommandSender {
private boolean colored = true;
@Override
@ -80,7 +82,7 @@ public class GeyserStandaloneLogger extends SimpleTerminalConsole implements Gey
@Override
public void info(String message) {
log.info(printConsole(ChatColor.RESET + ChatColor.BOLD + message, colored));
log.info(printConsole(ChatColor.WHITE + message, colored));
}
@Override
@ -94,11 +96,7 @@ public class GeyserStandaloneLogger extends SimpleTerminalConsole implements Gey
@Override
public void setDebug(boolean debug) {
Configurator.setLevel(log.getName(), debug ? Level.DEBUG : Level.INFO);
}
public boolean isDebug() {
return log.isDebugEnabled();
Configurator.setLevel(log.getName(), debug ? org.apache.logging.log4j.Level.DEBUG : log.getLevel());
}
@Override

View File

@ -1,38 +1,12 @@
/*
* Copyright (c) 2019-2021 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/Geyser
*/
package org.geysermc.platform.standalone;
import org.geysermc.connector.common.ChatColor;
import org.geysermc.connector.utils.LanguageUtils;
import java.io.InputStream;
import java.nio.file.Files;
import java.nio.file.OpenOption;
import java.nio.file.Paths;
import org.geysermc.common.ChatColor;
public class LoopbackUtil {
private static final String checkExemption = "powershell -Command \"CheckNetIsolation LoopbackExempt -s\""; // Java's Exec feature runs as CMD, NetIsolation is only accessible from PowerShell.
private static final String loopbackCommand = "powershell -Command \"CheckNetIsolation LoopbackExempt -a -n='Microsoft.MinecraftUWP_8wekyb3d8bbwe'\"";
@ -57,12 +31,12 @@ public class LoopbackUtil {
Files.write(Paths.get(System.getenv("temp") + "/loopback_minecraft.bat"), loopbackCommand.getBytes(), new OpenOption[0]);
process = Runtime.getRuntime().exec(startScript);
geyserLogger.info(ChatColor.AQUA + LanguageUtils.getLocaleStringLog("geyser.bootstrap.loopback.added"));
geyserLogger.info(ChatColor.AQUA + "Added loopback exemption to Windows!");
}
} catch (Exception e) {
e.printStackTrace();
geyserLogger.error(LanguageUtils.getLocaleStringLog("geyser.bootstrap.loopback.failed"));
geyserLogger.error("Couldn't auto add loopback exemption to Windows!");
}
}
}

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2019-2021 GeyserMC. http://geysermc.org
* Copyright (c) 2019-2020 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

View File

@ -1,78 +0,0 @@
/*
* Copyright (c) 2019-2021 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/Geyser
*/
package org.geysermc.platform.standalone.gui;
import lombok.Getter;
import java.awt.*;
import java.util.regex.Pattern;
public enum ANSIColor {
// Normal colors
BLACK("(0;)?30(0;)?m", Color.getHSBColor(0.000f, 0.000f, 0.000f)),
RED("(0;)?31(0;)?m", Color.getHSBColor(0.000f, 1.000f, 0.502f)),
GREEN("(0;)?32(0;)?m", Color.getHSBColor(0.333f, 1.000f, 0.502f)),
YELLOW("(0;)?33(0;)?m", Color.getHSBColor(0.167f, 1.000f, 0.502f)),
BLUE("(0;)?34(0;)?m", Color.getHSBColor(0.667f, 1.000f, 0.502f)),
MAGENTA("(0;)?35(0;)?m", Color.getHSBColor(0.833f, 1.000f, 0.502f)),
CYAN("(0;)?36(0;)?m", Color.getHSBColor(0.500f, 1.000f, 0.502f)),
WHITE("(0;)?37(0;)?m", Color.getHSBColor(0.000f, 0.000f, 0.753f)),
// Bold colors
B_BLACK("(1;30|30;1)m", Color.getHSBColor(0.000f, 0.000f, 0.502f)),
B_RED("(1;31|31;1)m", Color.getHSBColor(0.000f, 1.000f, 1.000f)),
B_GREEN("(1;32|32;1)m", Color.getHSBColor(0.333f, 1.000f, 1.000f)),
B_YELLOW("(1;33|33;1)m", Color.getHSBColor(0.167f, 1.000f, 1.000f)),
B_BLUE("(1;34|34;1)m", Color.getHSBColor(0.667f, 1.000f, 1.000f)),
B_MAGENTA("(1;35|35;1)m", Color.getHSBColor(0.833f, 1.000f, 1.000f)),
B_CYAN("(1;36|36;1)m", Color.getHSBColor(0.500f, 1.000f, 1.000f)),
B_WHITE("(1;37|37;1)m", Color.getHSBColor(0.000f, 0.000f, 1.000f)),
RESET("0m", Color.getHSBColor(0.000f, 0.000f, 1.000f));
private static final ANSIColor[] VALUES = values();
private static final String PREFIX = Pattern.quote("\u001B[");
private final String ANSICode;
@Getter
private final Color color;
ANSIColor(String ANSICode, Color color) {
this.ANSICode = ANSICode;
this.color = color;
}
public static ANSIColor fromANSI(String code) {
for (ANSIColor value : VALUES) {
if (code.matches(PREFIX + value.ANSICode)) {
return value;
}
}
return B_WHITE;
}
}

View File

@ -1,117 +0,0 @@
/*
* Copyright (c) 2019-2021 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/Geyser
*/
package org.geysermc.platform.standalone.gui;
import javax.swing.*;
import javax.swing.text.*;
import java.awt.*;
/**
* This class was based on this code: https://stackoverflow.com/a/6899478/5299903
*/
public class ColorPane extends JTextPane {
private static Color colorCurrent = ANSIColor.RESET.getColor();
private String remaining = "";
/**
* Append the given string in the given color to the text pane
* @param c The color
* @param s The text
*/
private void append(Color c, String s) {
StyleContext sc = StyleContext.getDefaultStyleContext();
AttributeSet aset = sc.addAttribute(SimpleAttributeSet.EMPTY, StyleConstants.Foreground, c);
int len = getDocument().getLength();
try {
getDocument().insertString(len, s, aset);
} catch (BadLocationException e) {
e.printStackTrace();
}
}
/**
* Extract the ANSI color codes from the string and add each part to the text pane
*
* @param s The text to parse
*/
public void appendANSI(String s) { // convert ANSI color codes first
int aPos = 0; // current char position in addString
int aIndex = 0; // index of next Escape sequence
int mIndex = 0; // index of "m" terminating Escape sequence
String tmpString = "";
boolean stillSearching = true; // true until no more Escape sequences
String addString = remaining + s;
remaining = "";
if (addString.length() > 0) {
aIndex = addString.indexOf("\u001B"); // find first escape
if (aIndex == -1) { // no escape/color change in this string, so just send it with current color
append(colorCurrent, addString);
return;
}
// otherwise There is an escape character in the string, so we must process it
if (aIndex > 0) { // Escape is not first char, so send text up to first escape
tmpString = addString.substring(0, aIndex);
append(colorCurrent, tmpString);
aPos = aIndex; // aPos is now at the beginning of the first escape sequence
}
// while there's text in the input buffer
stillSearching = true;
while (stillSearching) {
mIndex = addString.indexOf("m", aPos); // find the end of the escape sequence
if (mIndex < 0) { // the buffer ends halfway through the ansi string!
remaining = addString.substring(aPos, addString.length());
stillSearching = false;
continue;
} else {
tmpString = addString.substring(aPos, mIndex+1);
colorCurrent = ANSIColor.fromANSI(tmpString).getColor();
}
aPos = mIndex + 1;
// now we have the color, send text that is in that color (up to next escape)
aIndex = addString.indexOf("\u001B", aPos);
if (aIndex == -1) { // if that was the last sequence of the input, send remaining text
tmpString = addString.substring(aPos, addString.length());
append(colorCurrent, tmpString);
stillSearching = false;
continue; // jump out of loop early, as the whole string has been sent now
}
// there is another escape sequence, so send part of the string and prepare for the next
tmpString = addString.substring(aPos, aIndex);
aPos = aIndex;
append(colorCurrent, tmpString);
}
}
}
}

View File

@ -1,355 +0,0 @@
/*
* Copyright (c) 2019-2021 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/Geyser
*/
package org.geysermc.platform.standalone.gui;
import org.geysermc.connector.GeyserConnector;
import org.geysermc.connector.command.GeyserCommand;
import org.geysermc.connector.network.session.GeyserSession;
import org.geysermc.connector.utils.LanguageUtils;
import org.geysermc.platform.standalone.GeyserStandaloneLogger;
import org.geysermc.platform.standalone.command.GeyserCommandManager;
import javax.swing.*;
import javax.swing.table.DefaultTableModel;
import javax.swing.text.Document;
import java.awt.*;
import java.awt.event.*;
import java.io.File;
import java.io.IOException;
import java.io.OutputStream;
import java.io.PrintStream;
import java.net.URL;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Vector;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
public class GeyserStandaloneGUI {
private static final DefaultTableModel playerTableModel = new DefaultTableModel();
private static final List<Integer> ramValues = new ArrayList<>();
private static final ColorPane consolePane = new ColorPane();
private static final GraphPanel ramGraph = new GraphPanel();
private static final JTable playerTable = new JTable(playerTableModel);
private static final int originalFontSize = consolePane.getFont().getSize();
private static final long MEGABYTE = 1024L * 1024L;
private final JMenu commandsMenu;
private final JMenu optionsMenu;
public GeyserStandaloneGUI() {
// Create the frame and setup basic settings
JFrame frame = new JFrame(LanguageUtils.getLocaleStringLog("geyser.gui.title"));
frame.setDefaultCloseOperation(JFrame.DO_NOTHING_ON_CLOSE);
frame.setSize(800, 400);
frame.setMinimumSize(frame.getSize());
// Remove Java UI look
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (Exception ignored) { }
// Show a confirm dialog on close
frame.addWindowListener(new WindowAdapter() {
@Override
public void windowClosing(WindowEvent we)
{
String[] buttons = {LanguageUtils.getLocaleStringLog("geyser.gui.exit.confirm"), LanguageUtils.getLocaleStringLog("geyser.gui.exit.deny")};
int result = JOptionPane.showOptionDialog(frame, LanguageUtils.getLocaleStringLog("geyser.gui.exit.message"), frame.getTitle(), JOptionPane.YES_NO_OPTION, JOptionPane.WARNING_MESSAGE, null, buttons, buttons[1]);
if (result == JOptionPane.YES_OPTION) {
System.exit(0);
}
}
});
Container cp = frame.getContentPane();
// Fetch and set the icon for the frame
URL image = getClass().getClassLoader().getResource("icon.png");
if (image != null) {
ImageIcon icon = new ImageIcon(image);
frame.setIconImage(icon.getImage());
}
// Setup the split pane and event listeners
JSplitPane splitPane = new JSplitPane();
splitPane.setDividerLocation(600);
splitPane.addPropertyChangeListener("dividerLocation", e -> splitPaneLimit((JSplitPane)e.getSource()));
splitPane.addComponentListener(new ComponentAdapter() {
public void componentResized(ComponentEvent e) {
splitPaneLimit((JSplitPane)e.getSource());
}
});
cp.add(splitPane, BorderLayout.CENTER);
// Set the background and disable input for the text pane
consolePane.setBackground(Color.BLACK);
consolePane.setEditable(false);
// Wrap the text pane in a scroll pane and add it to the form
JScrollPane consoleScrollPane = new JScrollPane(consolePane);
//cp.add(consoleScrollPane, BorderLayout.CENTER);
splitPane.setLeftComponent(consoleScrollPane);
// Create a new menu bar for the top of the frame
JMenuBar menuBar = new JMenuBar();
// Create 'File'
JMenu fileMenu = new JMenu(LanguageUtils.getLocaleStringLog("geyser.gui.menu.file"));
fileMenu.setMnemonic(KeyEvent.VK_F);
menuBar.add(fileMenu);
// 'Open Geyser folder' button
JMenuItem openButton = new JMenuItem(LanguageUtils.getLocaleStringLog("geyser.gui.menu.file.open_folder"), KeyEvent.VK_O);
openButton.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_O, InputEvent.CTRL_MASK));
openButton.addActionListener(e -> {
try {
Desktop.getDesktop().open(new File("./"));
} catch (IOException ignored) { }
});
fileMenu.add(openButton);
fileMenu.addSeparator();
// 'Exit' button
JMenuItem exitButton = new JMenuItem(LanguageUtils.getLocaleStringLog("geyser.gui.menu.file.exit"), KeyEvent.VK_X);
exitButton.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_F4, InputEvent.ALT_MASK));
exitButton.addActionListener(e -> System.exit(0));
fileMenu.add(exitButton);
// Create 'Commands'
commandsMenu = new JMenu(LanguageUtils.getLocaleStringLog("geyser.gui.menu.commands"));
commandsMenu.setMnemonic(KeyEvent.VK_C);
menuBar.add(commandsMenu);
// Create 'View'
JMenu viewMenu = new JMenu(LanguageUtils.getLocaleStringLog("geyser.gui.menu.view"));
viewMenu.setMnemonic(KeyEvent.VK_V);
menuBar.add(viewMenu);
// 'Zoom in' button
JMenuItem zoomInButton = new JMenuItem(LanguageUtils.getLocaleStringLog("geyser.gui.menu.view.zoom_in"));
zoomInButton.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_EQUALS, InputEvent.CTRL_DOWN_MASK));
zoomInButton.addActionListener(e -> consolePane.setFont(new Font(consolePane.getFont().getName(), consolePane.getFont().getStyle(), consolePane.getFont().getSize() + 1)));
viewMenu.add(zoomInButton);
// 'Zoom in' button
JMenuItem zoomOutButton = new JMenuItem(LanguageUtils.getLocaleStringLog("geyser.gui.menu.view.zoom_out"));
zoomOutButton.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_MINUS, InputEvent.CTRL_DOWN_MASK));
zoomOutButton.addActionListener(e -> consolePane.setFont(new Font(consolePane.getFont().getName(), consolePane.getFont().getStyle(), consolePane.getFont().getSize() - 1)));
viewMenu.add(zoomOutButton);
// 'Reset Zoom' button
JMenuItem resetZoomButton = new JMenuItem(LanguageUtils.getLocaleStringLog("geyser.gui.menu.view.reset_zoom"));
resetZoomButton.addActionListener(e -> consolePane.setFont(new Font(consolePane.getFont().getName(), consolePane.getFont().getStyle(), originalFontSize)));
viewMenu.add(resetZoomButton);
// create 'Options'
optionsMenu = new JMenu(LanguageUtils.getLocaleStringLog("geyser.gui.menu.options"));
viewMenu.setMnemonic(KeyEvent.VK_O);
menuBar.add(optionsMenu);
// Set the frames menu bar
frame.setJMenuBar(menuBar);
JPanel rightPane = new JPanel();
rightPane.setLayout(new CardLayout(5, 5));
//cp.add(rightPane, BorderLayout.EAST);
splitPane.setRightComponent(rightPane);
JPanel rightContentPane = new JPanel();
rightContentPane.setLayout(new GridLayout(2, 1, 5, 5));
rightPane.add(rightContentPane);
// Set the ram graph to 0
for (int i = 0; i < 10; i++) {
ramValues.add(0);
}
ramGraph.setValues(ramValues);
ramGraph.setXLabel(LanguageUtils.getLocaleStringLog("geyser.gui.graph.loading"));
rightContentPane.add(ramGraph);
playerTableModel.addColumn(LanguageUtils.getLocaleStringLog("geyser.gui.table.ip"));
playerTableModel.addColumn(LanguageUtils.getLocaleStringLog("geyser.gui.table.username"));
JScrollPane playerScrollPane = new JScrollPane(playerTable);
rightContentPane.add(playerScrollPane);
// This has to be done last
frame.setVisible(true);
}
/**
* Queue up an update to the text pane so we don't block the main thread
*
* @param text The text to append
*/
private void updateTextPane(final String text) {
SwingUtilities.invokeLater(() -> {
consolePane.appendANSI(text);
Document doc = consolePane.getDocument();
consolePane.setCaretPosition(doc.getLength());
});
}
/**
* Redirect the default io streams to the text pane
*/
public void redirectSystemStreams() {
// Setup a new output stream to forward it to the text pane
OutputStream out = new OutputStream() {
@Override
public void write(final int b) {
updateTextPane(String.valueOf((char) b));
}
@Override
public void write(byte[] b, int off, int len) {
updateTextPane(new String(b, off, len));
}
@Override
public void write(byte[] b) {
write(b, 0, b.length);
}
};
// Override the system output streams
System.setOut(new PrintStream(out, true));
System.setErr(new PrintStream(out, true));
}
/**
* Add all the Geyser commands to the commands menu, and setup the debug mode toggle
*
* @param geyserStandaloneLogger The current logger
* @param geyserCommandManager The commands manager
*/
public void setupInterface(GeyserStandaloneLogger geyserStandaloneLogger, GeyserCommandManager geyserCommandManager) {
commandsMenu.removeAll();
optionsMenu.removeAll();
for (Map.Entry<String, GeyserCommand> command : geyserCommandManager.getCommands().entrySet()) {
// Remove the offhand command and any alias commands to prevent duplicates in the list
if (!command.getValue().isExecutableOnConsole() || command.getValue().getAliases().contains(command.getKey())) {
continue;
}
// Create the button that runs the command
boolean hasSubCommands = command.getValue().hasSubCommands();
// Add an extra menu if there are more commands that can be run
JMenuItem commandButton = hasSubCommands ? new JMenu(command.getValue().getName()) : new JMenuItem(command.getValue().getName());
commandButton.getAccessibleContext().setAccessibleDescription(command.getValue().getDescription());
if (!hasSubCommands) {
commandButton.addActionListener(e -> command.getValue().execute(geyserStandaloneLogger, new String[]{ }));
} else {
// Add a submenu that's the same name as the menu can't be pressed
JMenuItem otherCommandButton = new JMenuItem(command.getValue().getName());
otherCommandButton.getAccessibleContext().setAccessibleDescription(command.getValue().getDescription());
otherCommandButton.addActionListener(e -> command.getValue().execute(geyserStandaloneLogger, new String[]{ }));
commandButton.add(otherCommandButton);
// Add a menu option for all possible subcommands
for (String subCommandName : command.getValue().getSubCommands()) {
JMenuItem item = new JMenuItem(subCommandName);
item.addActionListener(e -> command.getValue().execute(geyserStandaloneLogger, new String[]{subCommandName}));
commandButton.add(item);
}
}
commandsMenu.add(commandButton);
}
// 'Debug Mode' toggle
JCheckBoxMenuItem debugMode = new JCheckBoxMenuItem(LanguageUtils.getLocaleStringLog("geyser.gui.menu.options.toggle_debug_mode"));
debugMode.setSelected(geyserStandaloneLogger.isDebug());
debugMode.addActionListener(e -> geyserStandaloneLogger.setDebug(!geyserStandaloneLogger.isDebug()));
optionsMenu.add(debugMode);
}
/**
* Start the thread to update the form information every 1s
*/
public void startUpdateThread() {
ScheduledExecutorService executor = Executors.newSingleThreadScheduledExecutor();
Runnable periodicTask = () -> {
if (GeyserConnector.getInstance() != null) {
// Update player table
playerTableModel.getDataVector().removeAllElements();
for (GeyserSession player : GeyserConnector.getInstance().getPlayers()) {
Vector<String> row = new Vector<>();
row.add(player.getSocketAddress().getHostName());
row.add(player.getPlayerEntity().getUsername());
playerTableModel.addRow(row);
}
playerTableModel.fireTableDataChanged();
}
// Update ram graph
final long freeMemory = Runtime.getRuntime().freeMemory();
final long totalMemory = Runtime.getRuntime().totalMemory();
final int freePercent = (int)(freeMemory * 100.0 / totalMemory + 0.5);
ramValues.add(100 - freePercent);
ramGraph.setXLabel(LanguageUtils.getLocaleStringLog("geyser.gui.graph.usage", String.format("%,d", (totalMemory - freeMemory) / MEGABYTE), freePercent));
// Trim the list
int k = ramValues.size();
if ( k > 10 )
ramValues.subList(0, k - 10).clear();
// Update the graph
ramGraph.setValues(ramValues);
};
// SwingUtilities.invokeLater is called so we don't run into threading issues with the GUI
executor.scheduleAtFixedRate(() -> SwingUtilities.invokeLater(periodicTask), 0, 1, TimeUnit.SECONDS);
}
/**
* Make sure the JSplitPane divider is within a set of bounds
*
* @param splitPane The JSplitPane to check
*/
private void splitPaneLimit(JSplitPane splitPane) {
JRootPane frame = splitPane.getRootPane();
int location = splitPane.getDividerLocation();
if (location < frame.getWidth() - frame.getWidth() * 0.4f) {
splitPane.setDividerLocation(Math.round(frame.getWidth() - frame.getWidth() * 0.4f));
} else if (location > frame.getWidth() - 200) {
splitPane.setDividerLocation(frame.getWidth() - 200);
}
}
}

View File

@ -1,187 +0,0 @@
/*
* Copyright (c) 2019-2021 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/Geyser
*/
package org.geysermc.platform.standalone.gui;
import lombok.Setter;
import javax.swing.*;
import java.awt.*;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
/**
* This has been modified to fit Geyser more but is based on
* https://gist.github.com/roooodcastro/6325153#gistcomment-3107524
*/
public final class GraphPanel extends JPanel {
private final static int padding = 10;
private final static int labelPadding = 25;
private final static int pointWidth = 4;
private final static int numberYDivisions = 10;
private final static Color lineColor = new Color(44, 102, 230, 255);
private final static Color pointColor = new Color(100, 100, 100, 255);
private final static Color gridColor = new Color(200, 200, 200, 255);
private static final Stroke graphStroke = new BasicStroke(2f);
private List<Integer> values = new ArrayList<>(10);
@Setter
private String xLabel = "";
public GraphPanel() {
setPreferredSize(new Dimension(200 - (padding * 2), 150 - (padding * 2)));
}
public void setValues(Collection<Integer> newValues) {
values.clear();
addValues(newValues);
}
public void addValues(Collection<Integer> newValues) {
values.addAll(newValues);
updateUI();
}
@Override
protected void paintComponent(Graphics graphics) {
super.paintComponent(graphics);
if (!(graphics instanceof Graphics2D)) {
graphics.drawString("Graphics is not Graphics2D, unable to render", 0, 0);
return;
}
final Graphics2D g = (Graphics2D) graphics;
g.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
final int length = values.size();
final int width = getWidth();
final int height = getHeight();
final int maxScore = getMaxScore();
final int minScore = getMinScore();
final int scoreRange = maxScore - minScore;
// draw white background
g.setColor(Color.WHITE);
g.fillRect(
padding + labelPadding,
padding,
width - (2 * padding) - labelPadding,
height - 2 * padding - labelPadding);
g.setColor(Color.BLACK);
final FontMetrics fontMetrics = g.getFontMetrics();
final int fontHeight = fontMetrics.getHeight();
// create hatch marks and grid lines for y axis.
for (int i = 0; i < numberYDivisions + 1; i++) {
final int x1 = padding + labelPadding;
final int x2 = pointWidth + padding + labelPadding;
final int y = height - ((i * (height - padding * 2 - labelPadding)) / numberYDivisions + padding + labelPadding);
if (length > 0) {
g.setColor(gridColor);
g.drawLine(padding + labelPadding + 1 + pointWidth, y, width - padding, y);
g.setColor(Color.BLACK);
final int tickValue = (int) (minScore + ((scoreRange * i) / numberYDivisions));
final String yLabel = tickValue + "";
final int labelWidth = fontMetrics.stringWidth(yLabel);
g.drawString(yLabel, x1 - labelWidth - 5, y + (fontHeight / 2) - 3);
}
g.drawLine(x1, y, x2, y);
}
// and for x axis
if (length > 1) {
for (int i = 0; i < length; i++) {
final int x = i * (width - padding * 2 - labelPadding) / (length - 1) + padding + labelPadding;
final int y1 = height - padding - labelPadding;
final int y2 = y1 - pointWidth;
if ((i % ((int) ((length / 20.0)) + 1)) == 0) {
g.setColor(gridColor);
g.drawLine(x, height - padding - labelPadding - 1 - pointWidth, x, padding);
g.setColor(Color.BLACK);
/*g.setColor(Color.BLACK);
final String xLabel = i + "";
final int labelWidth = fontMetrics.stringWidth(xLabel);
g.drawString(xLabel, x - labelWidth / 2, y1 + fontHeight + 3);*/
}
g.drawLine(x, y1, x, y2);
}
}
// create x and y axes
g.drawLine(padding + labelPadding, height - padding - labelPadding, padding + labelPadding, padding);
g.drawLine(padding + labelPadding, height - padding - labelPadding, width - padding, height - padding - labelPadding);
g.setColor(Color.BLACK);
final int labelWidth = fontMetrics.stringWidth(xLabel);
final int labelX = ((padding + labelPadding) + (width - padding)) / 2;
final int labelY = height - padding - labelPadding;
g.drawString(xLabel, labelX - labelWidth / 2, labelY + fontHeight + 3);
final Stroke oldStroke = g.getStroke();
g.setColor(lineColor);
g.setStroke(graphStroke);
final double xScale = ((double) width - (2 * padding) - labelPadding) / (length - 1);
final double yScale = ((double) height - 2 * padding - labelPadding) / scoreRange;
final List<Point> graphPoints = new ArrayList<>(length);
for (int i = 0; i < length; i++) {
final int x1 = (int) (i * xScale + padding + labelPadding);
final int y1 = (int) ((maxScore - values.get(i)) * yScale + padding);
graphPoints.add(new Point(x1, y1));
}
for (int i = 0; i < graphPoints.size() - 1; i++) {
final int x1 = graphPoints.get(i).x;
final int y1 = graphPoints.get(i).y;
final int x2 = graphPoints.get(i + 1).x;
final int y2 = graphPoints.get(i + 1).y;
g.drawLine(x1, y1, x2, y2);
}
boolean drawDots = width > (length * pointWidth);
if (drawDots) {
g.setStroke(oldStroke);
g.setColor(pointColor);
for (Point graphPoint : graphPoints) {
final int x = graphPoint.x - pointWidth / 2;
final int y = graphPoint.y - pointWidth / 2;
g.fillOval(x, y, pointWidth, pointWidth);
}
}
}
private int getMinScore() {
return 0;
}
private int getMaxScore() {
return 100;
}
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 113 KiB

View File

@ -1,12 +1,9 @@
<?xml version="1.0" encoding="UTF-8"?>
<Configuration status="WARN">
<Appenders>
<TerminalConsole name="TerminalConsole">
<TerminalConsole name="Console">
<PatternLayout pattern="[%d{HH:mm:ss} %style{%highlight{%level}{FATAL=red dark, ERROR=red, WARN=yellow bright, INFO=cyan bright, DEBUG=green, TRACE=white}}] %minecraftFormatting{%msg}%n"/>
</TerminalConsole>
<Console name="Console" target="SYSTEM_OUT" follow="true">
<PatternLayout pattern="[%d{HH:mm:ss} %style{%highlight{%level}{FATAL=red dark, ERROR=red, WARN=yellow bright, INFO=cyan bright, DEBUG=green, TRACE=white}}] %minecraftFormatting{%msg}%n"/>
</Console>
<RollingRandomAccessFile name="File" fileName="logs/latest.log" filePattern="logs/%d{yyyy-MM-dd}-%i.log.gz">
<PatternLayout pattern="%d{yyy-MM-dd HH:mm:ss.SSS} [%t] %level{length=1} - %msg%n"/>
<Policies>
@ -17,7 +14,6 @@
</Appenders>
<Loggers>
<Root level="INFO">
<AppenderRef ref="TerminalConsole"/>
<AppenderRef ref="Console"/>
<AppenderRef ref="File"/>
</Root>

View File

@ -6,21 +6,21 @@
<parent>
<groupId>org.geysermc</groupId>
<artifactId>bootstrap-parent</artifactId>
<version>1.2.0-SNAPSHOT</version>
<version>1.0-SNAPSHOT</version>
<relativePath>../</relativePath>
</parent>
<artifactId>bootstrap-velocity</artifactId>
<dependencies>
<dependency>
<groupId>org.geysermc</groupId>
<artifactId>connector</artifactId>
<version>1.2.0-SNAPSHOT</version>
<version>1.0-SNAPSHOT</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>com.velocitypowered</groupId>
<artifactId>velocity-api</artifactId>
<version>1.1.0</version>
<version>1.0.0-SNAPSHOT</version>
<scope>provided</scope>
</dependency>
</dependencies>
@ -57,34 +57,10 @@
</goals>
<configuration>
<relocations>
<relocation>
<pattern>com.fasterxml.jackson</pattern>
<shadedPattern>org.geysermc.platform.velocity.shaded.jackson</shadedPattern>
</relocation>
<relocation>
<pattern>it.unimi.dsi.fastutil</pattern>
<shadedPattern>org.geysermc.platform.velocity.shaded.fastutil</shadedPattern>
</relocation>
<relocation>
<pattern>org.reflections</pattern>
<shadedPattern>org.geysermc.platform.velocity.shaded.reflections</shadedPattern>
</relocation>
<relocation>
<pattern>com.google.common</pattern>
<shadedPattern>org.geysermc.platform.velocity.shaded.google.common</shadedPattern>
</relocation>
<relocation>
<pattern>com.google.guava</pattern>
<shadedPattern>org.geysermc.platform.velocity.shaded.google.guava</shadedPattern>
</relocation>
<relocation>
<pattern>org.dom4j</pattern>
<shadedPattern>org.geysermc.platform.velocity.shaded.dom4j</shadedPattern>
</relocation>
<relocation>
<pattern>net.kyori</pattern>
<shadedPattern>org.geysermc.platform.velocity.shaded.kyori</shadedPattern>
</relocation>
</relocations>
</configuration>
</execution>
@ -93,16 +69,7 @@
<artifactSet>
<excludes>
<exclude>com.google.code.gson:*</exclude>
<!-- Needed because Velocity provides every dependency except netty-resolver-dns -->
<exclude>io.netty:netty-transport-native-epoll:*</exclude>
<exclude>io.netty:netty-transport-native-unix-common:*</exclude>
<exclude>io.netty:netty-transport-native-kqueue:*</exclude>
<exclude>io.netty:netty-handler:*</exclude>
<exclude>io.netty:netty-common:*</exclude>
<exclude>io.netty:netty-buffer:*</exclude>
<exclude>io.netty:netty-resolver:*</exclude>
<exclude>io.netty:netty-transport:*</exclude>
<exclude>io.netty:netty-codec:*</exclude>
<exclude>io.netty:*</exclude>
<exclude>org.slf4j:*</exclude>
<exclude>org.ow2.asm:*</exclude>
</excludes>

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2019-2021 GeyserMC. http://geysermc.org
* Copyright (c) 2019-2020 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
@ -25,26 +25,127 @@
package org.geysermc.platform.velocity;
import com.fasterxml.jackson.annotation.JsonIgnore;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.velocitypowered.api.plugin.PluginContainer;
import com.velocitypowered.api.proxy.ProxyServer;
import lombok.Getter;
import lombok.Setter;
import org.geysermc.connector.FloodgateKeyLoader;
import org.geysermc.connector.configuration.GeyserJacksonConfiguration;
import org.geysermc.connector.GeyserConfiguration;
import java.io.File;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.Map;
import java.util.Optional;
@Getter
@JsonIgnoreProperties(ignoreUnknown = true)
public final class GeyserVelocityConfiguration extends GeyserJacksonConfiguration {
@JsonIgnore
private Path floodgateKeyPath;
@Getter
public class GeyserVelocityConfiguration implements GeyserConfiguration {
private BedrockConfiguration bedrock;
private RemoteConfiguration remote;
@JsonProperty("floodgate-key-file")
private String floodgateKeyFile;
private Map<String, UserAuthenticationInfo> userAuths;
@JsonProperty("command-suggestions")
private boolean commandSuggestions;
@JsonProperty("passthrough-motd")
private boolean isPassthroughMotd;
@JsonProperty("passthrough-player-counts")
private boolean isPassthroughPlayerCounts;
@JsonProperty("legacy-ping-passthrough")
private boolean isLegacyPingPassthrough;
@JsonProperty("ping-passthrough-interval")
private int pingPassthroughInterval;
@JsonProperty("max-players")
private int maxPlayers;
@JsonProperty("debug-mode")
private boolean debugMode;
@JsonProperty("general-thread-pool")
private int generalThreadPool;
@JsonProperty("allow-third-party-capes")
private boolean allowThirdPartyCapes;
@JsonProperty("allow-third-party-ears")
private boolean allowThirdPartyEars;
@JsonProperty("default-locale")
private String defaultLocale;
@JsonProperty("cache-chunks")
private boolean cacheChunks;
@JsonProperty("above-bedrock-nether-building")
private boolean aboveBedrockNetherBuilding;
private MetricsInfo metrics;
private Path floodgateKey;
public void loadFloodgate(GeyserVelocityPlugin plugin, ProxyServer proxyServer, File dataFolder) {
PluginContainer floodgate = proxyServer.getPluginManager().getPlugin("floodgate").orElse(null);
floodgateKeyPath = FloodgateKeyLoader.getKeyPath(this, floodgate, Paths.get("plugins/floodgate/"), dataFolder.toPath(), plugin.getGeyserLogger());
Optional<PluginContainer> floodgate = proxyServer.getPluginManager().getPlugin("floodgate");
floodgate.ifPresent(it -> floodgateKey = FloodgateKeyLoader.getKey(plugin.getGeyserLogger(), this, Paths.get(dataFolder.toString(), floodgateKeyFile.isEmpty() ? floodgateKeyFile : "public-key.pem"), it, Paths.get("plugins/floodgate/")));
}
@Override
public Path getFloodgateKeyFile() {
return floodgateKey;
}
@Getter
public static class BedrockConfiguration implements IBedrockConfiguration {
private String address;
private int port;
private String motd1;
private String motd2;
}
@Getter
public static class RemoteConfiguration implements IRemoteConfiguration {
@Setter
private String address;
@Setter
private int port;
private String motd1;
private String motd2;
@JsonProperty("auth-type")
private String authType;
}
@Getter
public static class UserAuthenticationInfo implements IUserAuthenticationInfo {
private String email;
private String password;
}
@Getter
public static class MetricsInfo implements IMetricsInfo {
private boolean enabled;
@JsonProperty("uuid")
private String uniqueId;
}
@JsonProperty("config-version")
private int configVersion;
}

View File

@ -1,67 +0,0 @@
/*
* Copyright (c) 2019-2021 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/Geyser
*/
package org.geysermc.platform.velocity;
import com.velocitypowered.api.plugin.PluginContainer;
import com.velocitypowered.api.proxy.ProxyServer;
import lombok.Getter;
import org.geysermc.connector.common.serializer.AsteriskSerializer;
import org.geysermc.connector.dump.BootstrapDumpInfo;
import java.util.ArrayList;
import java.util.List;
@Getter
public class GeyserVelocityDumpInfo extends BootstrapDumpInfo {
private String platformName;
private String platformVersion;
private String platformVendor;
private boolean onlineMode;
private String serverIP;
private int serverPort;
private List<PluginInfo> plugins;
GeyserVelocityDumpInfo(ProxyServer proxy) {
super();
this.platformName = proxy.getVersion().getName();
this.platformVersion = proxy.getVersion().getVersion();
this.platformVendor = proxy.getVersion().getVendor();
this.onlineMode = proxy.getConfiguration().isOnlineMode();
if (AsteriskSerializer.showSensitive || (proxy.getBoundAddress().getHostString().equals("") || proxy.getBoundAddress().getHostString().equals("0.0.0.0"))) {
this.serverIP = proxy.getBoundAddress().getHostString();
} else {
this.serverIP = "***";
}
this.serverPort = proxy.getBoundAddress().getPort();
this.plugins = new ArrayList<>();
for (PluginContainer plugin : proxy.getPluginManager().getPlugins()) {
String pluginClass = plugin.getInstance().map((pl) -> pl.getClass().getName()).orElse("unknown");
this.plugins.add(new PluginInfo(true, plugin.getDescription().getName().get(), plugin.getDescription().getVersion().get(), pluginClass, plugin.getDescription().getAuthors()));
}
}
}

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2019-2021 GeyserMC. http://geysermc.org
* Copyright (c) 2019-2020 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
@ -26,16 +26,15 @@
package org.geysermc.platform.velocity;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.Setter;
import org.geysermc.connector.GeyserLogger;
import org.slf4j.Logger;
@AllArgsConstructor
public class GeyserVelocityLogger implements GeyserLogger {
private final Logger logger;
@Getter @Setter
private boolean debug;
private Logger logger;
private boolean debugMode;
@Override
public void severe(String message) {
@ -69,8 +68,12 @@ public class GeyserVelocityLogger implements GeyserLogger {
@Override
public void debug(String message) {
if (debug) {
if (debugMode)
info(message);
}
}
@Override
public void setDebug(boolean debugMode) {
this.debugMode = debugMode;
}
}

View File

@ -1,31 +1,32 @@
/*
* Copyright (c) 2019-2021 GeyserMC. http://geysermc.org
* Copyright (c) 2019-2020 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:
* 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 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.
* 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/Geyser
*
* @author GeyserMC
* @link https://github.com/GeyserMC/Geyser
*/
package org.geysermc.platform.velocity;
import org.geysermc.connector.common.main.IGeyserMain;
import org.geysermc.common.main.IGeyserMain;
public class GeyserVelocityMain extends IGeyserMain {

View File

@ -1,26 +1,27 @@
/*
* Copyright (c) 2019-2021 GeyserMC. http://geysermc.org
* Copyright (c) 2019-2020 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:
* 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 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.
* 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/Geyser
*
* @author GeyserMC
* @link https://github.com/GeyserMC/Geyser
*/
package org.geysermc.platform.velocity;
@ -31,8 +32,9 @@ import com.velocitypowered.api.proxy.InboundConnection;
import com.velocitypowered.api.proxy.ProxyServer;
import com.velocitypowered.api.proxy.server.ServerPing;
import lombok.AllArgsConstructor;
import net.kyori.text.TextComponent;
import net.kyori.text.serializer.legacy.LegacyComponentSerializer;
import org.geysermc.connector.common.ping.GeyserPingInfo;
import org.geysermc.common.ping.GeyserPingInfo;
import org.geysermc.connector.ping.IGeyserPingPassthrough;
import java.net.Inet4Address;
@ -43,44 +45,38 @@ import java.util.concurrent.ExecutionException;
@AllArgsConstructor
public class GeyserVelocityPingPassthrough implements IGeyserPingPassthrough {
private static final GeyserInboundConnection FAKE_INBOUND_CONNECTION = new GeyserInboundConnection();
private final ProxyServer server;
@Override
public GeyserPingInfo getPingInformation(InetSocketAddress inetSocketAddress) {
public GeyserPingInfo getPingInformation() {
ProxyPingEvent event;
try {
event = server.getEventManager().fire(new ProxyPingEvent(new GeyserInboundConnection(inetSocketAddress), ServerPing.builder()
event = server.getEventManager().fire(new ProxyPingEvent(FAKE_INBOUND_CONNECTION, ServerPing.builder()
.description(server.getConfiguration().getMotdComponent()).onlinePlayers(server.getPlayerCount())
.maximumPlayers(server.getConfiguration().getShowMaxPlayers()).build())).get();
} catch (ExecutionException | InterruptedException e) {
throw new RuntimeException(e);
}
GeyserPingInfo geyserPingInfo = new GeyserPingInfo(
LegacyComponentSerializer.legacy().serialize(event.getPing().getDescription(), '§'),
new GeyserPingInfo.Players(
event.getPing().getPlayers().orElseThrow(IllegalStateException::new).getMax(),
event.getPing().getPlayers().orElseThrow(IllegalStateException::new).getOnline()
),
new GeyserPingInfo.Version(
event.getPing().getVersion().getName(),
event.getPing().getVersion().getProtocol()
)
LegacyComponentSerializer.INSTANCE.serialize(event.getPing().getDescription(), '§'),
event.getPing().getPlayers().orElseThrow(IllegalStateException::new).getOnline(),
event.getPing().getPlayers().orElseThrow(IllegalStateException::new).getMax()
);
event.getPing().getPlayers().get().getSample().stream().map(ServerPing.SamplePlayer::getName).forEach(geyserPingInfo.getPlayerList()::add);
event.getPing().getPlayers().get().getSample().forEach(player -> {
geyserPingInfo.addPlayer(player.getName());
});
return geyserPingInfo;
}
private static class GeyserInboundConnection implements InboundConnection {
private final InetSocketAddress remote;
public GeyserInboundConnection(InetSocketAddress remote) {
this.remote = remote;
}
private static final InetSocketAddress FAKE_REMOTE = new InetSocketAddress(Inet4Address.getLoopbackAddress(), 69);
@Override
public InetSocketAddress getRemoteAddress() {
return this.remote;
return FAKE_REMOTE;
}
@Override

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2019-2021 GeyserMC. http://geysermc.org
* Copyright (c) 2019-2020 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
@ -26,22 +26,21 @@
package org.geysermc.platform.velocity;
import com.google.inject.Inject;
import com.velocitypowered.api.command.CommandManager;
import com.velocitypowered.api.event.Subscribe;
import com.velocitypowered.api.event.proxy.ProxyInitializeEvent;
import com.velocitypowered.api.event.proxy.ProxyShutdownEvent;
import com.velocitypowered.api.plugin.Plugin;
import com.velocitypowered.api.proxy.ProxyServer;
import lombok.Getter;
import org.geysermc.common.PlatformType;
import org.geysermc.connector.GeyserConfiguration;
import org.geysermc.connector.GeyserConnector;
import org.geysermc.connector.bootstrap.GeyserBootstrap;
import org.geysermc.connector.configuration.GeyserConfiguration;
import org.geysermc.connector.dump.BootstrapDumpInfo;
import org.geysermc.connector.ping.GeyserLegacyPingPassthrough;
import org.geysermc.connector.ping.IGeyserPingPassthrough;
import org.geysermc.connector.utils.FileUtils;
import org.geysermc.connector.utils.LanguageUtils;
import org.geysermc.platform.velocity.command.GeyserVelocityCommandExecutor;
import org.geysermc.platform.velocity.command.GeyserVelocityCommandManager;
import org.slf4j.Logger;
@ -49,8 +48,6 @@ import org.slf4j.Logger;
import java.io.File;
import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.UUID;
@Plugin(id = "geyser", name = GeyserConnector.NAME + "-Velocity", version = GeyserConnector.VERSION, url = "https://geysermc.org", authors = "GeyserMC")
@ -72,56 +69,39 @@ public class GeyserVelocityPlugin implements GeyserBootstrap {
private GeyserConnector connector;
@Getter
private final Path configFolder = Paths.get("plugins/" + GeyserConnector.NAME + "-Velocity/");
@Override
public void onEnable() {
File configDir = new File("plugins/" + GeyserConnector.NAME + "-Velocity/");
try {
if (!configFolder.toFile().exists())
//noinspection ResultOfMethodCallIgnored
configFolder.toFile().mkdirs();
File configFile = FileUtils.fileOrCopiedFromResource(configFolder.resolve("config.yml").toFile(), "config.yml", (x) -> x.replaceAll("generateduuid", UUID.randomUUID().toString()));
if (!configDir.exists())
configDir.mkdir();
File configFile = FileUtils.fileOrCopiedFromResource(new File(configDir, "config.yml"), "config.yml", (x) -> x.replaceAll("generateduuid", UUID.randomUUID().toString()));
this.geyserConfig = FileUtils.loadConfig(configFile, GeyserVelocityConfiguration.class);
} catch (IOException ex) {
logger.warn(LanguageUtils.getLocaleStringLog("geyser.config.failed"), ex);
logger.warn("Failed to read/create config.yml! Make sure it's up to date and/or readable+writable!", ex);
ex.printStackTrace();
}
InetSocketAddress javaAddr = proxyServer.getBoundAddress();
// By default this should be localhost but may need to be changed in some circumstances
if (this.geyserConfig.getRemote().getAddress().equalsIgnoreCase("auto")) {
this.geyserConfig.setAutoconfiguredRemote(true);
// Don't use localhost if not listening on all interfaces
if (!javaAddr.getHostString().equals("0.0.0.0") && !javaAddr.getHostString().equals("")) {
this.geyserConfig.getRemote().setAddress(javaAddr.getHostString());
}
geyserConfig.getRemote().setPort(javaAddr.getPort());
// Don't change the ip if its listening on all interfaces
// By default this should be 127.0.0.1 but may need to be changed in some circumstances
if (!javaAddr.getHostString().equals("0.0.0.0") && !javaAddr.getHostString().equals("")) {
geyserConfig.getRemote().setAddress(javaAddr.getHostString());
}
if (geyserConfig.getBedrock().isCloneRemotePort()) {
geyserConfig.getBedrock().setPort(javaAddr.getPort());
}
geyserConfig.getRemote().setPort(javaAddr.getPort());
this.geyserLogger = new GeyserVelocityLogger(logger, geyserConfig.isDebugMode());
GeyserConfiguration.checkGeyserConfiguration(geyserConfig, geyserLogger);
if (geyserConfig.getRemote().getAuthType().equals("floodgate") && !proxyServer.getPluginManager().getPlugin("floodgate").isPresent()) {
geyserLogger.severe(LanguageUtils.getLocaleStringLog("geyser.bootstrap.floodgate.not_installed") + " " + LanguageUtils.getLocaleStringLog("geyser.bootstrap.floodgate.disabling"));
return;
} else if (geyserConfig.isAutoconfiguredRemote() && proxyServer.getPluginManager().getPlugin("floodgate").isPresent()) {
// Floodgate installed means that the user wants Floodgate authentication
geyserLogger.debug("Auto-setting to Floodgate authentication.");
geyserConfig.getRemote().setAuthType("floodgate");
}
geyserConfig.loadFloodgate(this, proxyServer, configFolder.toFile());
geyserConfig.loadFloodgate(this, proxyServer, configDir);
this.connector = GeyserConnector.start(PlatformType.VELOCITY, this);
this.geyserCommandManager = new GeyserVelocityCommandManager(connector);
this.commandManager.register("geyser", new GeyserVelocityCommandExecutor(connector));
this.commandManager.register(new GeyserVelocityCommandExecutor(connector), "geyser");
if (geyserConfig.isLegacyPingPassthrough()) {
this.geyserPingPassthrough = GeyserLegacyPingPassthrough.init(connector);
} else {
@ -163,9 +143,4 @@ public class GeyserVelocityPlugin implements GeyserBootstrap {
public void onShutdown(ProxyShutdownEvent event) {
onDisable();
}
@Override
public BootstrapDumpInfo getDumpInfo() {
return new GeyserVelocityDumpInfo(proxyServer);
}
}

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2019-2021 GeyserMC. http://geysermc.org
* Copyright (c) 2019-2020 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
@ -25,48 +25,37 @@
package org.geysermc.platform.velocity.command;
import com.velocitypowered.api.command.Command;
import com.velocitypowered.api.command.CommandSource;
import com.velocitypowered.api.command.SimpleCommand;
import lombok.AllArgsConstructor;
import org.geysermc.connector.GeyserConnector;
import org.geysermc.connector.command.CommandSender;
import org.geysermc.connector.command.GeyserCommand;
import org.geysermc.connector.common.ChatColor;
import org.geysermc.connector.utils.LanguageUtils;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import lombok.AllArgsConstructor;
import net.kyori.text.TextComponent;
import org.geysermc.common.ChatColor;
import org.geysermc.connector.GeyserConnector;
import org.geysermc.connector.command.GeyserCommand;
@AllArgsConstructor
public class GeyserVelocityCommandExecutor implements SimpleCommand {
public class GeyserVelocityCommandExecutor implements Command {
private final GeyserConnector connector;
private GeyserConnector connector;
@Override
public void execute(Invocation invocation) {
if (invocation.arguments().length > 0) {
if (getCommand(invocation.arguments()[0]) != null) {
if (!invocation.source().hasPermission(getCommand(invocation.arguments()[0]).getPermission())) {
CommandSender sender = new VelocityCommandSender(invocation.source());
sender.sendMessage(ChatColor.RED + LanguageUtils.getPlayerLocaleString("geyser.bootstrap.command.permission_fail", sender.getLocale()));
public void execute(CommandSource source, String[] args) {
if (args.length > 0) {
if (getCommand(args[0]) != null) {
if (!source.hasPermission(getCommand(args[0]).getPermission())) {
source.sendMessage(TextComponent.of(ChatColor.RED + "You do not have permission to execute this command!"));
return;
}
getCommand(invocation.arguments()[0]).execute(new VelocityCommandSender(invocation.source()), invocation.arguments().length > 1 ? Arrays.copyOfRange(invocation.arguments(), 1, invocation.arguments().length) : new String[0]);
getCommand(args[0]).execute(new VelocityCommandSender(source), args);
}
} else {
getCommand("help").execute(new VelocityCommandSender(invocation.source()), new String[0]);
getCommand("help").execute(new VelocityCommandSender(source), args);
}
}
@Override
public List<String> suggest(Invocation invocation) {
if (invocation.arguments().length == 0) {
return connector.getCommandManager().getCommandNames();
}
return new ArrayList<>();
}
private GeyserCommand getCommand(String label) {
return connector.getCommandManager().getCommands().get(label);
}

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2019-2021 GeyserMC. http://geysermc.org
* Copyright (c) 2019-2020 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

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2019-2021 GeyserMC. http://geysermc.org
* Copyright (c) 2019-2020 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
@ -28,21 +28,17 @@ package org.geysermc.platform.velocity.command;
import com.velocitypowered.api.command.CommandSource;
import com.velocitypowered.api.proxy.ConsoleCommandSource;
import com.velocitypowered.api.proxy.Player;
import lombok.AllArgsConstructor;
import net.kyori.text.TextComponent;
import org.geysermc.connector.command.CommandSender;
import org.geysermc.connector.utils.LanguageUtils;
import java.util.Locale;
@AllArgsConstructor
public class VelocityCommandSender implements CommandSender {
private final CommandSource handle;
public VelocityCommandSender(CommandSource handle) {
this.handle = handle;
// Ensure even Java players' languages are loaded
LanguageUtils.loadGeyserLocale(getLocale());
}
private CommandSource handle;
@Override
public String getName() {
@ -63,13 +59,4 @@ public class VelocityCommandSender implements CommandSender {
public boolean isConsole() {
return handle instanceof ConsoleCommandSource;
}
@Override
public String getLocale() {
if (handle instanceof Player) {
Locale locale = ((Player) handle).getPlayerSettings().getLocale();
return LanguageUtils.formatLocale(locale.getLanguage() + "_" + locale.getCountry());
}
return LanguageUtils.getDefaultLocale();
}
}

View File

@ -6,10 +6,11 @@
<parent>
<groupId>org.geysermc</groupId>
<artifactId>geyser-parent</artifactId>
<version>1.2.0-SNAPSHOT</version>
<version>parent</version>
<relativePath>../</relativePath>
</parent>
<artifactId>common</artifactId>
<version>1.0-SNAPSHOT</version>
<dependencies>
<dependency>
<groupId>com.google.code.gson</groupId>

View File

@ -0,0 +1,33 @@
package org.geysermc.common;
import lombok.Getter;
@Getter
public enum AuthType {
OFFLINE,
ONLINE,
FLOODGATE;
public static final AuthType[] VALUES = values();
public static AuthType getById(int id) {
return id < VALUES.length ? VALUES[id] : OFFLINE;
}
/**
* Convert the AuthType string (from config) to the enum, OFFLINE on fail
*
* @param name AuthType string
*
* @return The converted AuthType
*/
public static AuthType getByName(String name) {
String upperCase = name.toUpperCase();
for (AuthType type : VALUES) {
if (type.name().equals(upperCase)) {
return type;
}
}
return OFFLINE;
}
}

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2019-2021 GeyserMC. http://geysermc.org
* Copyright (c) 2019-2020 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
@ -23,7 +23,7 @@
* @link https://github.com/GeyserMC/Geyser
*/
package org.geysermc.connector.common;
package org.geysermc.common;
public class ChatColor {

View File

@ -1,28 +1,3 @@
/*
* Copyright (c) 2019-2021 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/Geyser
*/
package org.geysermc.common;
import lombok.AllArgsConstructor;
@ -32,13 +7,11 @@ import lombok.Getter;
@AllArgsConstructor
public enum PlatformType {
ANDROID("Android"),
BUKKIT("Bukkit"),
BUNGEECORD("BungeeCord"),
FABRIC("Fabric"),
SPIGOT("Spigot"),
SPONGE("Sponge"),
STANDALONE("Standalone"),
VELOCITY("Velocity");
private final String platformName;
private String platformName;
}

View File

@ -0,0 +1,74 @@
/*
* Copyright (c) 2019-2020 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/Geyser
*
*/
package org.geysermc.common.main;
import javax.swing.*;
import java.io.InputStream;
import java.util.Scanner;
public class IGeyserMain {
public void displayMessage() {
String message = createMessage();
if (System.console() == null) {
JOptionPane.showMessageDialog(null, message, "GeyserMC Plugin: " + this.getPluginType(), JOptionPane.ERROR_MESSAGE);
}
printMessage(message);
}
private String createMessage() {
String message = "";
InputStream helpStream = IGeyserMain.class.getClassLoader().getResourceAsStream("help.txt");
Scanner help = new Scanner(helpStream).useDelimiter("\\Z");
String line = "";
while (help.hasNext()) {
line = help.next();
line = line.replace("${plugin_type}", this.getPluginType());
line = line.replace("${plugin_folder}", this.getPluginFolder());
message += line + "\n";
}
return message;
}
private void printMessage(String message) {
System.out.print(message);
}
public String getPluginType() {
return "unknown";
}
public String getPluginFolder() {
return "unknown";
}
}

View File

@ -0,0 +1,48 @@
/*
* Copyright (c) 2019-2020 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/Geyser
*
*/
package org.geysermc.common.ping;
import lombok.Data;
import lombok.Getter;
import java.util.ArrayList;
import java.util.Collection;
@Data
public class GeyserPingInfo {
public final String motd;
public final int currentPlayerCount;
public final int maxPlayerCount;
@Getter
private Collection<String> players = new ArrayList<>();
public void addPlayer(String username) {
players.add(username);
}
}

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2019-2021 GeyserMC. http://geysermc.org
* Copyright (c) 2019-2020 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

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2019-2021 GeyserMC. http://geysermc.org
* Copyright (c) 2019-2020 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
@ -92,7 +92,7 @@ public class CustomFormWindow extends FormWindow {
}
public void setResponse(String data) {
if (data == null || data.trim().equalsIgnoreCase("null") || data.isEmpty()) {
if (data == null || data.equalsIgnoreCase("null") || data.isEmpty()) {
closed = true;
return;
}
@ -108,7 +108,7 @@ public class CustomFormWindow extends FormWindow {
List<String> componentResponses = new ArrayList<>();
try {
componentResponses = new ObjectMapper().readValue(data.trim(), new TypeReference<List<String>>(){});
componentResponses = new ObjectMapper().readValue(data, new TypeReference<List<String>>(){});
} catch (IOException e) { }
for (String response : componentResponses) {

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2019-2021 GeyserMC. http://geysermc.org
* Copyright (c) 2019-2020 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

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2019-2021 GeyserMC. http://geysermc.org
* Copyright (c) 2019-2020 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

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2019-2021 GeyserMC. http://geysermc.org
* Copyright (c) 2019-2020 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
@ -72,14 +72,14 @@ public class SimpleFormWindow extends FormWindow {
}
public void setResponse(String data) {
if (data == null || data.trim().equalsIgnoreCase("null")) {
if (data == null || data.equalsIgnoreCase("null")) {
closed = true;
return;
}
int buttonID;
try {
buttonID = Integer.parseInt(data.trim());
buttonID = Integer.parseInt(data);
} catch (Exception ex) {
return;
}

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2019-2021 GeyserMC. http://geysermc.org
* Copyright (c) 2019-2020 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

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2019-2021 GeyserMC. http://geysermc.org
* Copyright (c) 2019-2020 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
@ -32,14 +32,14 @@ public class FormImage {
@Getter
@Setter
private String type;
private FormImageType type;
@Getter
@Setter
private String data;
public FormImage(FormImageType type, String data) {
this.type = type.getName();
this.type = type;
this.data = data;
}

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2019-2021 GeyserMC. http://geysermc.org
* Copyright (c) 2019-2020 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

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2019-2021 GeyserMC. http://geysermc.org
* Copyright (c) 2019-2020 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

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2019-2021 GeyserMC. http://geysermc.org
* Copyright (c) 2019-2020 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

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2019-2021 GeyserMC. http://geysermc.org
* Copyright (c) 2019-2020 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

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2019-2021 GeyserMC. http://geysermc.org
* Copyright (c) 2019-2020 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

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2019-2021 GeyserMC. http://geysermc.org
* Copyright (c) 2019-2020 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

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2019-2021 GeyserMC. http://geysermc.org
* Copyright (c) 2019-2020 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
@ -25,17 +25,9 @@
package org.geysermc.common.window.component;
import lombok.Getter;
import lombok.Setter;
public class ToggleComponent extends FormComponent {
@Getter
@Setter
private String text;
@Getter
@Setter
private boolean defaultValue;
public ToggleComponent(String text) {

Some files were not shown because too many files have changed in this diff Show More