forked from GeyserMC/Geyser
Merge branch 'master' into resources
This commit is contained in:
commit
ddd21aef25
292 changed files with 11779 additions and 2539 deletions
1
.gitignore
vendored
1
.gitignore
vendored
|
@ -222,6 +222,7 @@ nbdist/
|
||||||
# End of https://www.gitignore.io/api/git,java,maven,eclipse,netbeans,jetbrains+all
|
# End of https://www.gitignore.io/api/git,java,maven,eclipse,netbeans,jetbrains+all
|
||||||
|
|
||||||
### Geyser ###
|
### Geyser ###
|
||||||
|
run/
|
||||||
config.yml
|
config.yml
|
||||||
logs/
|
logs/
|
||||||
public-key.pem
|
public-key.pem
|
||||||
|
|
|
@ -9,10 +9,14 @@
|
||||||
|
|
||||||
Geyser is a bridge between Minecraft: Bedrock Edition and Minecraft: Java Edition, closing the gap from those wanting to play true cross-platform.
|
Geyser is a bridge between Minecraft: Bedrock Edition and Minecraft: Java Edition, closing the gap from those wanting to play true cross-platform.
|
||||||
|
|
||||||
|
Geyser is an open collaboration project by [CubeCraft Games](https://cubecraft.net).
|
||||||
|
|
||||||
## What is Geyser?
|
## What is Geyser?
|
||||||
Geyser is a proxy, bridging the gap between Minecraft: Bedrock Edition and Minecraft: Java Edition servers.
|
Geyser is a proxy, bridging the gap between Minecraft: Bedrock Edition and Minecraft: Java Edition servers.
|
||||||
The ultimate goal of this project is to allow Minecraft: Bedrock Edition users to join Minecraft: Java Edition servers as seamlessly as possible. **Please note, this project is still a work in progress and should not be used on production. Expect bugs!**
|
The ultimate goal of this project is to allow Minecraft: Bedrock Edition users to join Minecraft: Java Edition servers as seamlessly as possible. **Please note, this project is still a work in progress and should not be used on production. Expect bugs!**
|
||||||
|
|
||||||
|
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.14.6(0) and Minecraft Java v1.15.2.
|
### Currently supporting Minecraft Bedrock v1.14.6(0) and Minecraft Java v1.15.2.
|
||||||
|
|
||||||
## Setting Up
|
## Setting Up
|
||||||
|
@ -34,8 +38,6 @@ Take a look [here](https://github.com/GeyserMC/Geyser/wiki#Setup) for how to set
|
||||||
- [ ] Cartography Table
|
- [ ] Cartography Table
|
||||||
- [ ] Stonecutter
|
- [ ] Stonecutter
|
||||||
- [ ] Villager Trading
|
- [ ] Villager Trading
|
||||||
- Sounds
|
|
||||||
- Block Particles
|
|
||||||
- Some Entity Flags
|
- Some Entity Flags
|
||||||
|
|
||||||
## Compiling
|
## Compiling
|
||||||
|
|
|
@ -23,6 +23,12 @@
|
||||||
<version>1.14-R0.1-SNAPSHOT</version>
|
<version>1.14-R0.1-SNAPSHOT</version>
|
||||||
<scope>provided</scope>
|
<scope>provided</scope>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>us.myles</groupId>
|
||||||
|
<artifactId>viaversion</artifactId>
|
||||||
|
<version>3.0.0-SNAPSHOT</version>
|
||||||
|
<scope>provided</scope>
|
||||||
|
</dependency>
|
||||||
</dependencies>
|
</dependencies>
|
||||||
<build>
|
<build>
|
||||||
<finalName>${outputName}-Bukkit</finalName>
|
<finalName>${outputName}-Bukkit</finalName>
|
||||||
|
@ -33,6 +39,18 @@
|
||||||
</resource>
|
</resource>
|
||||||
</resources>
|
</resources>
|
||||||
<plugins>
|
<plugins>
|
||||||
|
<plugin>
|
||||||
|
<groupId>org.apache.maven.plugins</groupId>
|
||||||
|
<artifactId>maven-jar-plugin</artifactId>
|
||||||
|
<version>3.2.0</version>
|
||||||
|
<configuration>
|
||||||
|
<archive>
|
||||||
|
<manifestEntries>
|
||||||
|
<Main-Class>org.geysermc.platform.bukkit.GeyserBukkitMain</Main-Class>
|
||||||
|
</manifestEntries>
|
||||||
|
</archive>
|
||||||
|
</configuration>
|
||||||
|
</plugin>
|
||||||
<plugin>
|
<plugin>
|
||||||
<groupId>org.apache.maven.plugins</groupId>
|
<groupId>org.apache.maven.plugins</groupId>
|
||||||
<artifactId>maven-shade-plugin</artifactId>
|
<artifactId>maven-shade-plugin</artifactId>
|
||||||
|
@ -58,14 +76,6 @@
|
||||||
</execution>
|
</execution>
|
||||||
</executions>
|
</executions>
|
||||||
<configuration>
|
<configuration>
|
||||||
<filters>
|
|
||||||
<filter>
|
|
||||||
<artifact>*:*</artifact>
|
|
||||||
<excludes>
|
|
||||||
<exclude>META-INF/*</exclude>
|
|
||||||
</excludes>
|
|
||||||
</filter>
|
|
||||||
</filters>
|
|
||||||
<artifactSet>
|
<artifactSet>
|
||||||
<excludes>
|
<excludes>
|
||||||
<exclude>com.google.code.gson:*</exclude>
|
<exclude>com.google.code.gson:*</exclude>
|
||||||
|
|
|
@ -25,8 +25,11 @@
|
||||||
|
|
||||||
package org.geysermc.platform.bukkit;
|
package org.geysermc.platform.bukkit;
|
||||||
|
|
||||||
|
import org.bukkit.Bukkit;
|
||||||
import org.bukkit.configuration.file.FileConfiguration;
|
import org.bukkit.configuration.file.FileConfiguration;
|
||||||
import org.geysermc.common.IGeyserConfiguration;
|
import org.bukkit.plugin.Plugin;
|
||||||
|
import org.geysermc.connector.FloodgateKeyLoader;
|
||||||
|
import org.geysermc.connector.GeyserConfiguration;
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.nio.file.Path;
|
import java.nio.file.Path;
|
||||||
|
@ -34,7 +37,7 @@ import java.nio.file.Paths;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
public class GeyserBukkitConfiguration implements IGeyserConfiguration {
|
public class GeyserBukkitConfiguration implements GeyserConfiguration {
|
||||||
|
|
||||||
private FileConfiguration config;
|
private FileConfiguration config;
|
||||||
private File dataFolder;
|
private File dataFolder;
|
||||||
|
@ -45,6 +48,8 @@ public class GeyserBukkitConfiguration implements IGeyserConfiguration {
|
||||||
|
|
||||||
private Map<String, BukkitUserAuthenticationInfo> userAuthInfo = new HashMap<>();
|
private Map<String, BukkitUserAuthenticationInfo> userAuthInfo = new HashMap<>();
|
||||||
|
|
||||||
|
private Path floodgateKey;
|
||||||
|
|
||||||
public GeyserBukkitConfiguration(File dataFolder, FileConfiguration config) {
|
public GeyserBukkitConfiguration(File dataFolder, FileConfiguration config) {
|
||||||
this.dataFolder = dataFolder;
|
this.dataFolder = dataFolder;
|
||||||
this.config = config;
|
this.config = config;
|
||||||
|
@ -61,6 +66,11 @@ public class GeyserBukkitConfiguration implements IGeyserConfiguration {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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
|
@Override
|
||||||
public IBedrockConfiguration getBedrock() {
|
public IBedrockConfiguration getBedrock() {
|
||||||
return bedrockConfig;
|
return bedrockConfig;
|
||||||
|
@ -77,8 +87,28 @@ public class GeyserBukkitConfiguration implements IGeyserConfiguration {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean isPingPassthrough() {
|
public boolean isCommandSuggestions() {
|
||||||
return config.getBoolean("ping-passthrough", false);
|
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
|
@Override
|
||||||
|
@ -101,6 +131,11 @@ public class GeyserBukkitConfiguration implements IGeyserConfiguration {
|
||||||
return config.getBoolean("allow-third-party-capes", true);
|
return config.getBoolean("allow-third-party-capes", true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isAllowThirdPartyEars() {
|
||||||
|
return config.getBoolean("allow-third-party-ears", false);
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String getDefaultLocale() {
|
public String getDefaultLocale() {
|
||||||
return config.getString("default-locale", "en_us");
|
return config.getString("default-locale", "en_us");
|
||||||
|
@ -108,7 +143,17 @@ public class GeyserBukkitConfiguration implements IGeyserConfiguration {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Path getFloodgateKeyFile() {
|
public Path getFloodgateKeyFile() {
|
||||||
return Paths.get(dataFolder.toString(), config.getString("floodgate-key-file", "public-key.pem"));
|
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
|
@Override
|
||||||
|
@ -188,4 +233,9 @@ public class GeyserBukkitConfiguration implements IGeyserConfiguration {
|
||||||
return config.getString("metrics.uuid", "generateduuid");
|
return config.getString("metrics.uuid", "generateduuid");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getConfigVersion() {
|
||||||
|
return config.getInt("config-version", 0);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -27,13 +27,13 @@ package org.geysermc.platform.bukkit;
|
||||||
|
|
||||||
import lombok.AllArgsConstructor;
|
import lombok.AllArgsConstructor;
|
||||||
|
|
||||||
import org.geysermc.common.logger.IGeyserLogger;
|
import org.geysermc.connector.GeyserLogger;
|
||||||
|
|
||||||
import java.util.logging.Level;
|
import java.util.logging.Level;
|
||||||
import java.util.logging.Logger;
|
import java.util.logging.Logger;
|
||||||
|
|
||||||
@AllArgsConstructor
|
@AllArgsConstructor
|
||||||
public class GeyserBukkitLogger implements IGeyserLogger {
|
public class GeyserBukkitLogger implements GeyserLogger {
|
||||||
|
|
||||||
private Logger logger;
|
private Logger logger;
|
||||||
private boolean debugMode;
|
private boolean debugMode;
|
||||||
|
|
|
@ -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";
|
||||||
|
}
|
||||||
|
}
|
|
@ -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();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -28,19 +28,29 @@ package org.geysermc.platform.bukkit;
|
||||||
import org.bukkit.Bukkit;
|
import org.bukkit.Bukkit;
|
||||||
import org.bukkit.plugin.java.JavaPlugin;
|
import org.bukkit.plugin.java.JavaPlugin;
|
||||||
import org.geysermc.common.PlatformType;
|
import org.geysermc.common.PlatformType;
|
||||||
import org.geysermc.common.bootstrap.IGeyserBootstrap;
|
import org.geysermc.connector.GeyserConfiguration;
|
||||||
import org.geysermc.connector.GeyserConnector;
|
import org.geysermc.connector.GeyserConnector;
|
||||||
|
import org.geysermc.connector.bootstrap.GeyserBootstrap;
|
||||||
import org.geysermc.connector.command.CommandManager;
|
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.GeyserBukkitCommandExecutor;
|
||||||
import org.geysermc.platform.bukkit.command.GeyserBukkitCommandManager;
|
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;
|
import java.util.UUID;
|
||||||
|
|
||||||
public class GeyserBukkitPlugin extends JavaPlugin implements IGeyserBootstrap {
|
public class GeyserBukkitPlugin extends JavaPlugin implements GeyserBootstrap {
|
||||||
|
|
||||||
private GeyserBukkitCommandManager geyserCommandManager;
|
private GeyserBukkitCommandManager geyserCommandManager;
|
||||||
private GeyserBukkitConfiguration geyserConfig;
|
private GeyserBukkitConfiguration geyserConfig;
|
||||||
private GeyserBukkitLogger geyserLogger;
|
private GeyserBukkitLogger geyserLogger;
|
||||||
|
private IGeyserPingPassthrough geyserBukkitPingPassthrough;
|
||||||
|
private GeyserBukkitBlockPlaceListener blockPlaceListener;
|
||||||
|
private GeyserBukkitWorldManager geyserWorldManager;
|
||||||
|
|
||||||
private GeyserConnector connector;
|
private GeyserConnector connector;
|
||||||
|
|
||||||
|
@ -56,7 +66,7 @@ public class GeyserBukkitPlugin extends JavaPlugin implements IGeyserBootstrap {
|
||||||
|
|
||||||
// Don't change the ip if its listening on all interfaces
|
// 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
|
// 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")) {
|
if (!Bukkit.getIp().equals("0.0.0.0") && !Bukkit.getIp().equals("")) {
|
||||||
getConfig().set("remote.address", Bukkit.getIp());
|
getConfig().set("remote.address", Bukkit.getIp());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -64,10 +74,40 @@ public class GeyserBukkitPlugin extends JavaPlugin implements IGeyserBootstrap {
|
||||||
saveConfig();
|
saveConfig();
|
||||||
|
|
||||||
this.geyserLogger = new GeyserBukkitLogger(getLogger(), geyserConfig.isDebugMode());
|
this.geyserLogger = new GeyserBukkitLogger(getLogger(), geyserConfig.isDebugMode());
|
||||||
|
GeyserConfiguration.checkGeyserConfiguration(geyserConfig, geyserLogger);
|
||||||
|
|
||||||
|
geyserConfig.loadFloodgate(this);
|
||||||
|
|
||||||
this.connector = GeyserConnector.start(PlatformType.BUKKIT, 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);
|
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));
|
this.getCommand("geyser").setExecutor(new GeyserBukkitCommandExecutor(connector));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -90,4 +130,48 @@ public class GeyserBukkitPlugin extends JavaPlugin implements IGeyserBootstrap {
|
||||||
public CommandManager getGeyserCommandManager() {
|
public CommandManager getGeyserCommandManager() {
|
||||||
return this.geyserCommandManager;
|
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;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -3,6 +3,8 @@ name: ${outputName}-Bukkit
|
||||||
author: ${project.organization.name}
|
author: ${project.organization.name}
|
||||||
website: ${project.organization.url}
|
website: ${project.organization.url}
|
||||||
version: ${project.version}
|
version: ${project.version}
|
||||||
|
softdepend: ["ViaVersion"]
|
||||||
|
api-version: 1.13
|
||||||
commands:
|
commands:
|
||||||
geyser:
|
geyser:
|
||||||
description: The main command for Geyser.
|
description: The main command for Geyser.
|
||||||
|
|
|
@ -20,7 +20,7 @@
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>net.md-5</groupId>
|
<groupId>net.md-5</groupId>
|
||||||
<artifactId>bungeecord-api</artifactId>
|
<artifactId>bungeecord-api</artifactId>
|
||||||
<version>1.14-SNAPSHOT</version>
|
<version>1.15-SNAPSHOT</version>
|
||||||
<scope>provided</scope>
|
<scope>provided</scope>
|
||||||
</dependency>
|
</dependency>
|
||||||
</dependencies>
|
</dependencies>
|
||||||
|
@ -33,6 +33,18 @@
|
||||||
</resource>
|
</resource>
|
||||||
</resources>
|
</resources>
|
||||||
<plugins>
|
<plugins>
|
||||||
|
<plugin>
|
||||||
|
<groupId>org.apache.maven.plugins</groupId>
|
||||||
|
<artifactId>maven-jar-plugin</artifactId>
|
||||||
|
<version>3.2.0</version>
|
||||||
|
<configuration>
|
||||||
|
<archive>
|
||||||
|
<manifestEntries>
|
||||||
|
<Main-Class>org.geysermc.platform.bungeecord.GeyserBungeeMain</Main-Class>
|
||||||
|
</manifestEntries>
|
||||||
|
</archive>
|
||||||
|
</configuration>
|
||||||
|
</plugin>
|
||||||
<plugin>
|
<plugin>
|
||||||
<groupId>org.apache.maven.plugins</groupId>
|
<groupId>org.apache.maven.plugins</groupId>
|
||||||
<artifactId>maven-shade-plugin</artifactId>
|
<artifactId>maven-shade-plugin</artifactId>
|
||||||
|
@ -58,14 +70,6 @@
|
||||||
</execution>
|
</execution>
|
||||||
</executions>
|
</executions>
|
||||||
<configuration>
|
<configuration>
|
||||||
<filters>
|
|
||||||
<filter>
|
|
||||||
<artifact>*:*</artifact>
|
|
||||||
<excludes>
|
|
||||||
<exclude>META-INF/*</exclude>
|
|
||||||
</excludes>
|
|
||||||
</filter>
|
|
||||||
</filters>
|
|
||||||
<artifactSet>
|
<artifactSet>
|
||||||
<excludes>
|
<excludes>
|
||||||
<exclude>com.google.code.gson:*</exclude>
|
<exclude>com.google.code.gson:*</exclude>
|
||||||
|
|
|
@ -25,9 +25,10 @@
|
||||||
|
|
||||||
package org.geysermc.platform.bungeecord;
|
package org.geysermc.platform.bungeecord;
|
||||||
|
|
||||||
|
import net.md_5.bungee.api.plugin.Plugin;
|
||||||
import net.md_5.bungee.config.Configuration;
|
import net.md_5.bungee.config.Configuration;
|
||||||
|
import org.geysermc.connector.FloodgateKeyLoader;
|
||||||
import org.geysermc.common.IGeyserConfiguration;
|
import org.geysermc.connector.GeyserConfiguration;
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.nio.file.Path;
|
import java.nio.file.Path;
|
||||||
|
@ -35,7 +36,7 @@ import java.nio.file.Paths;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
public class GeyserBungeeConfiguration implements IGeyserConfiguration {
|
public class GeyserBungeeConfiguration implements GeyserConfiguration {
|
||||||
|
|
||||||
private File dataFolder;
|
private File dataFolder;
|
||||||
private Configuration config;
|
private Configuration config;
|
||||||
|
@ -46,6 +47,8 @@ public class GeyserBungeeConfiguration implements IGeyserConfiguration {
|
||||||
|
|
||||||
private Map<String, BungeeUserAuthenticationInfo> userAuthInfo = new HashMap<>();
|
private Map<String, BungeeUserAuthenticationInfo> userAuthInfo = new HashMap<>();
|
||||||
|
|
||||||
|
private Path floodgateKey;
|
||||||
|
|
||||||
public GeyserBungeeConfiguration(File dataFolder, Configuration config) {
|
public GeyserBungeeConfiguration(File dataFolder, Configuration config) {
|
||||||
this.dataFolder = dataFolder;
|
this.dataFolder = dataFolder;
|
||||||
this.config = config;
|
this.config = config;
|
||||||
|
@ -62,6 +65,11 @@ public class GeyserBungeeConfiguration implements IGeyserConfiguration {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void loadFloodgate(GeyserBungeePlugin plugin) {
|
||||||
|
Plugin floodgate = plugin.getProxy().getPluginManager().getPlugin("floodgate-bungee");
|
||||||
|
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
|
@Override
|
||||||
public BungeeBedrockConfiguration getBedrock() {
|
public BungeeBedrockConfiguration getBedrock() {
|
||||||
return bedrockConfig;
|
return bedrockConfig;
|
||||||
|
@ -78,8 +86,28 @@ public class GeyserBungeeConfiguration implements IGeyserConfiguration {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean isPingPassthrough() {
|
public boolean isCommandSuggestions() {
|
||||||
return config.getBoolean("ping-passthrough", false);
|
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
|
@Override
|
||||||
|
@ -102,6 +130,11 @@ public class GeyserBungeeConfiguration implements IGeyserConfiguration {
|
||||||
return config.getBoolean("allow-third-party-capes", true);
|
return config.getBoolean("allow-third-party-capes", true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isAllowThirdPartyEars() {
|
||||||
|
return config.getBoolean("allow-third-party-ears", false);
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String getDefaultLocale() {
|
public String getDefaultLocale() {
|
||||||
return config.getString("default-locale", "en_us");
|
return config.getString("default-locale", "en_us");
|
||||||
|
@ -109,7 +142,17 @@ public class GeyserBungeeConfiguration implements IGeyserConfiguration {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Path getFloodgateKeyFile() {
|
public Path getFloodgateKeyFile() {
|
||||||
return Paths.get(dataFolder.toString(), config.getString("floodgate-key-file", "public-key.pem"));
|
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
|
@Override
|
||||||
|
@ -189,4 +232,9 @@ public class GeyserBungeeConfiguration implements IGeyserConfiguration {
|
||||||
return config.getString("metrics.uuid", "generateduuid");
|
return config.getString("metrics.uuid", "generateduuid");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getConfigVersion() {
|
||||||
|
return config.getInt("config-version", 0);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -25,12 +25,12 @@
|
||||||
|
|
||||||
package org.geysermc.platform.bungeecord;
|
package org.geysermc.platform.bungeecord;
|
||||||
|
|
||||||
import org.geysermc.common.logger.IGeyserLogger;
|
import org.geysermc.connector.GeyserLogger;
|
||||||
|
|
||||||
import java.util.logging.Level;
|
import java.util.logging.Level;
|
||||||
import java.util.logging.Logger;
|
import java.util.logging.Logger;
|
||||||
|
|
||||||
public class GeyserBungeeLogger implements IGeyserLogger {
|
public class GeyserBungeeLogger implements GeyserLogger {
|
||||||
|
|
||||||
private Logger logger;
|
private Logger logger;
|
||||||
private boolean debugMode;
|
private boolean debugMode;
|
||||||
|
|
|
@ -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.bungeecord;
|
||||||
|
|
||||||
|
import org.geysermc.common.main.IGeyserMain;
|
||||||
|
|
||||||
|
public class GeyserBungeeMain extends IGeyserMain {
|
||||||
|
|
||||||
|
public static void main(String[] args) {
|
||||||
|
new GeyserBungeeMain().displayMessage();
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getPluginType() {
|
||||||
|
return "BungeeCord";
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getPluginFolder() {
|
||||||
|
return "plugins";
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,180 @@
|
||||||
|
/*
|
||||||
|
* 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.bungeecord;
|
||||||
|
|
||||||
|
import lombok.AllArgsConstructor;
|
||||||
|
import net.md_5.bungee.api.ProxyServer;
|
||||||
|
import net.md_5.bungee.api.ServerPing;
|
||||||
|
import net.md_5.bungee.api.chat.BaseComponent;
|
||||||
|
import net.md_5.bungee.api.config.ListenerInfo;
|
||||||
|
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.common.ping.GeyserPingInfo;
|
||||||
|
import org.geysermc.connector.ping.IGeyserPingPassthrough;
|
||||||
|
|
||||||
|
import java.net.Inet4Address;
|
||||||
|
import java.net.InetSocketAddress;
|
||||||
|
import java.net.SocketAddress;
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.UUID;
|
||||||
|
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() {
|
||||||
|
CompletableFuture<ProxyPingEvent> future = new CompletableFuture<>();
|
||||||
|
proxyServer.getPluginManager().callEvent(new ProxyPingEvent(PENDING_CONNECTION, getPingInfo(), (event, throwable) -> {
|
||||||
|
if (throwable != null) future.completeExceptionally(throwable);
|
||||||
|
else future.complete(event);
|
||||||
|
}));
|
||||||
|
ProxyPingEvent event = future.join();
|
||||||
|
GeyserPingInfo geyserPingInfo = new GeyserPingInfo(
|
||||||
|
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.addPlayer(proxiedPlayer.getName());
|
||||||
|
});
|
||||||
|
}
|
||||||
|
return geyserPingInfo;
|
||||||
|
}
|
||||||
|
|
||||||
|
// This is static so pending connection can use it
|
||||||
|
private static ListenerInfo getDefaultListener() {
|
||||||
|
return ProxyServer.getInstance().getConfig().getListeners().iterator().next();
|
||||||
|
}
|
||||||
|
|
||||||
|
private ServerPing getPingInfo() {
|
||||||
|
return new ServerPing(
|
||||||
|
new ServerPing.Protocol(proxyServer.getName() + " " + proxyServer.getGameVersion(), ProtocolConstants.SUPPORTED_VERSION_IDS.get(ProtocolConstants.SUPPORTED_VERSION_IDS.size() - 1)),
|
||||||
|
new ServerPing.Players(getDefaultListener().getMaxPlayers(), proxyServer.getOnlineCount(), null),
|
||||||
|
getDefaultListener().getMotd(), proxyServer.getConfig().getFaviconObject()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static class GeyserPendingConnection implements PendingConnection {
|
||||||
|
|
||||||
|
private static final UUID FAKE_UUID = UUID.nameUUIDFromBytes("geyser!internal".getBytes());
|
||||||
|
private static final InetSocketAddress FAKE_REMOTE = new InetSocketAddress(Inet4Address.getLoopbackAddress(), 69);
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getName() {
|
||||||
|
throw new UnsupportedOperationException();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getVersion() {
|
||||||
|
return ProtocolConstants.SUPPORTED_VERSION_IDS.get(ProtocolConstants.SUPPORTED_VERSION_IDS.size() - 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public InetSocketAddress getVirtualHost() {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ListenerInfo getListener() {
|
||||||
|
return getDefaultListener();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getUUID() {
|
||||||
|
return FAKE_UUID.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public UUID getUniqueId() {
|
||||||
|
return FAKE_UUID;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setUniqueId(UUID uuid) {
|
||||||
|
throw new UnsupportedOperationException();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isOnlineMode() {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setOnlineMode(boolean b) {
|
||||||
|
throw new UnsupportedOperationException();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isLegacy() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public InetSocketAddress getAddress() {
|
||||||
|
return FAKE_REMOTE;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public SocketAddress getSocketAddress() {
|
||||||
|
return getAddress();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void disconnect(String s) {
|
||||||
|
throw new UnsupportedOperationException();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void disconnect(BaseComponent... baseComponents) {
|
||||||
|
throw new UnsupportedOperationException();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void disconnect(BaseComponent baseComponent) {
|
||||||
|
throw new UnsupportedOperationException();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isConnected() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Unsafe unsafe() {
|
||||||
|
throw new UnsupportedOperationException();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -31,9 +31,12 @@ import net.md_5.bungee.config.Configuration;
|
||||||
import net.md_5.bungee.config.ConfigurationProvider;
|
import net.md_5.bungee.config.ConfigurationProvider;
|
||||||
import net.md_5.bungee.config.YamlConfiguration;
|
import net.md_5.bungee.config.YamlConfiguration;
|
||||||
import org.geysermc.common.PlatformType;
|
import org.geysermc.common.PlatformType;
|
||||||
import org.geysermc.common.bootstrap.IGeyserBootstrap;
|
import org.geysermc.connector.GeyserConfiguration;
|
||||||
import org.geysermc.connector.GeyserConnector;
|
import org.geysermc.connector.GeyserConnector;
|
||||||
|
import org.geysermc.connector.bootstrap.GeyserBootstrap;
|
||||||
import org.geysermc.connector.command.CommandManager;
|
import org.geysermc.connector.command.CommandManager;
|
||||||
|
import org.geysermc.connector.ping.GeyserLegacyPingPassthrough;
|
||||||
|
import org.geysermc.connector.ping.IGeyserPingPassthrough;
|
||||||
import org.geysermc.platform.bungeecord.command.GeyserBungeeCommandExecutor;
|
import org.geysermc.platform.bungeecord.command.GeyserBungeeCommandExecutor;
|
||||||
import org.geysermc.platform.bungeecord.command.GeyserBungeeCommandManager;
|
import org.geysermc.platform.bungeecord.command.GeyserBungeeCommandManager;
|
||||||
|
|
||||||
|
@ -45,11 +48,12 @@ import java.nio.file.Files;
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
import java.util.logging.Level;
|
import java.util.logging.Level;
|
||||||
|
|
||||||
public class GeyserBungeePlugin extends Plugin implements IGeyserBootstrap {
|
public class GeyserBungeePlugin extends Plugin implements GeyserBootstrap {
|
||||||
|
|
||||||
private GeyserBungeeCommandManager geyserCommandManager;
|
private GeyserBungeeCommandManager geyserCommandManager;
|
||||||
private GeyserBungeeConfiguration geyserConfig;
|
private GeyserBungeeConfiguration geyserConfig;
|
||||||
private GeyserBungeeLogger geyserLogger;
|
private GeyserBungeeLogger geyserLogger;
|
||||||
|
private IGeyserPingPassthrough geyserBungeePingPassthrough;
|
||||||
|
|
||||||
private GeyserConnector connector;
|
private GeyserConnector connector;
|
||||||
|
|
||||||
|
@ -91,7 +95,7 @@ public class GeyserBungeePlugin extends Plugin implements IGeyserBootstrap {
|
||||||
|
|
||||||
// Don't change the ip if its listening on all interfaces
|
// 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
|
// 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")) {
|
if (!javaAddr.getHostString().equals("0.0.0.0") && !javaAddr.getHostString().equals("")) {
|
||||||
configuration.set("remote.address", javaAddr.getHostString());
|
configuration.set("remote.address", javaAddr.getHostString());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -116,10 +120,20 @@ public class GeyserBungeePlugin extends Plugin implements IGeyserBootstrap {
|
||||||
}
|
}
|
||||||
|
|
||||||
this.geyserLogger = new GeyserBungeeLogger(getLogger(), geyserConfig.isDebugMode());
|
this.geyserLogger = new GeyserBungeeLogger(getLogger(), geyserConfig.isDebugMode());
|
||||||
|
GeyserConfiguration.checkGeyserConfiguration(geyserConfig, geyserLogger);
|
||||||
|
|
||||||
|
geyserConfig.loadFloodgate(this);
|
||||||
|
|
||||||
this.connector = GeyserConnector.start(PlatformType.BUNGEECORD, this);
|
this.connector = GeyserConnector.start(PlatformType.BUNGEECORD, this);
|
||||||
|
|
||||||
this.geyserCommandManager = new GeyserBungeeCommandManager(connector);
|
this.geyserCommandManager = new GeyserBungeeCommandManager(connector);
|
||||||
|
|
||||||
|
if (geyserConfig.isLegacyPingPassthrough()) {
|
||||||
|
this.geyserBungeePingPassthrough = GeyserLegacyPingPassthrough.init(connector);
|
||||||
|
} else {
|
||||||
|
this.geyserBungeePingPassthrough = new GeyserBungeePingPassthrough(getProxy());
|
||||||
|
}
|
||||||
|
|
||||||
this.getProxy().getPluginManager().registerCommand(this, new GeyserBungeeCommandExecutor(connector));
|
this.getProxy().getPluginManager().registerCommand(this, new GeyserBungeeCommandExecutor(connector));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -142,4 +156,9 @@ public class GeyserBungeePlugin extends Plugin implements IGeyserBootstrap {
|
||||||
public CommandManager getGeyserCommandManager() {
|
public CommandManager getGeyserCommandManager() {
|
||||||
return this.geyserCommandManager;
|
return this.geyserCommandManager;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public IGeyserPingPassthrough getGeyserPingPassthrough() {
|
||||||
|
return geyserBungeePingPassthrough;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -33,6 +33,18 @@
|
||||||
</resource>
|
</resource>
|
||||||
</resources>
|
</resources>
|
||||||
<plugins>
|
<plugins>
|
||||||
|
<plugin>
|
||||||
|
<groupId>org.apache.maven.plugins</groupId>
|
||||||
|
<artifactId>maven-jar-plugin</artifactId>
|
||||||
|
<version>3.2.0</version>
|
||||||
|
<configuration>
|
||||||
|
<archive>
|
||||||
|
<manifestEntries>
|
||||||
|
<Main-Class>org.geysermc.platform.sponge.GeyserSpongeMain</Main-Class>
|
||||||
|
</manifestEntries>
|
||||||
|
</archive>
|
||||||
|
</configuration>
|
||||||
|
</plugin>
|
||||||
<plugin>
|
<plugin>
|
||||||
<groupId>org.apache.maven.plugins</groupId>
|
<groupId>org.apache.maven.plugins</groupId>
|
||||||
<artifactId>maven-shade-plugin</artifactId>
|
<artifactId>maven-shade-plugin</artifactId>
|
||||||
|
@ -62,14 +74,6 @@
|
||||||
</execution>
|
</execution>
|
||||||
</executions>
|
</executions>
|
||||||
<configuration>
|
<configuration>
|
||||||
<filters>
|
|
||||||
<filter>
|
|
||||||
<artifact>*:*</artifact>
|
|
||||||
<excludes>
|
|
||||||
<exclude>META-INF/*</exclude>
|
|
||||||
</excludes>
|
|
||||||
</filter>
|
|
||||||
</filters>
|
|
||||||
<artifactSet>
|
<artifactSet>
|
||||||
<excludes>
|
<excludes>
|
||||||
<exclude>com.google.code.gson:*</exclude>
|
<exclude>com.google.code.gson:*</exclude>
|
||||||
|
|
|
@ -26,15 +26,17 @@
|
||||||
package org.geysermc.platform.sponge;
|
package org.geysermc.platform.sponge;
|
||||||
|
|
||||||
import lombok.AllArgsConstructor;
|
import lombok.AllArgsConstructor;
|
||||||
|
|
||||||
import ninja.leaping.configurate.ConfigurationNode;
|
import ninja.leaping.configurate.ConfigurationNode;
|
||||||
import org.geysermc.common.IGeyserConfiguration;
|
|
||||||
|
import org.geysermc.connector.GeyserConfiguration;
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.nio.file.Path;
|
import java.nio.file.Path;
|
||||||
import java.nio.file.Paths;
|
import java.nio.file.Paths;
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
|
|
||||||
public class GeyserSpongeConfiguration implements IGeyserConfiguration {
|
public class GeyserSpongeConfiguration implements GeyserConfiguration {
|
||||||
|
|
||||||
private File dataFolder;
|
private File dataFolder;
|
||||||
private ConfigurationNode node;
|
private ConfigurationNode node;
|
||||||
|
@ -78,8 +80,28 @@ public class GeyserSpongeConfiguration implements IGeyserConfiguration {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean isPingPassthrough() {
|
public boolean isCommandSuggestions() {
|
||||||
return node.getNode("ping-passthrough").getBoolean(false);
|
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
|
@Override
|
||||||
|
@ -102,6 +124,11 @@ public class GeyserSpongeConfiguration implements IGeyserConfiguration {
|
||||||
return node.getNode("allow-third-party-capes").getBoolean(true);
|
return node.getNode("allow-third-party-capes").getBoolean(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isAllowThirdPartyEars() {
|
||||||
|
return node.getNode("allow-third-party-ears").getBoolean(false);
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String getDefaultLocale() {
|
public String getDefaultLocale() {
|
||||||
return node.getNode("default-locale").getString("en_us");
|
return node.getNode("default-locale").getString("en_us");
|
||||||
|
@ -112,6 +139,16 @@ public class GeyserSpongeConfiguration implements IGeyserConfiguration {
|
||||||
return Paths.get(dataFolder.toString(), node.getNode("floodgate-key-file").getString("public-key.pem"));
|
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
|
@Override
|
||||||
public SpongeMetricsInfo getMetrics() {
|
public SpongeMetricsInfo getMetrics() {
|
||||||
return metricsInfo;
|
return metricsInfo;
|
||||||
|
@ -195,4 +232,9 @@ public class GeyserSpongeConfiguration implements IGeyserConfiguration {
|
||||||
return node.getNode("metrics").getNode("uuid").getString("generateduuid");
|
return node.getNode("metrics").getNode("uuid").getString("generateduuid");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getConfigVersion() {
|
||||||
|
return node.getNode("config-version").getInt(0);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -27,11 +27,11 @@ package org.geysermc.platform.sponge;
|
||||||
|
|
||||||
import lombok.AllArgsConstructor;
|
import lombok.AllArgsConstructor;
|
||||||
|
|
||||||
import org.geysermc.common.logger.IGeyserLogger;
|
import org.geysermc.connector.GeyserLogger;
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
|
|
||||||
@AllArgsConstructor
|
@AllArgsConstructor
|
||||||
public class GeyserSpongeLogger implements IGeyserLogger {
|
public class GeyserSpongeLogger implements GeyserLogger {
|
||||||
|
|
||||||
private Logger logger;
|
private Logger logger;
|
||||||
private boolean debugMode;
|
private boolean debugMode;
|
||||||
|
|
|
@ -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.sponge;
|
||||||
|
|
||||||
|
import org.geysermc.common.main.IGeyserMain;
|
||||||
|
|
||||||
|
public class GeyserSpongeMain extends IGeyserMain {
|
||||||
|
|
||||||
|
public static void main(String[] args) {
|
||||||
|
new GeyserSpongeMain().displayMessage();
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getPluginType() {
|
||||||
|
return "Sponge";
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getPluginFolder() {
|
||||||
|
return "mods";
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,99 @@
|
||||||
|
/*
|
||||||
|
* 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.sponge;
|
||||||
|
|
||||||
|
import org.geysermc.common.ping.GeyserPingInfo;
|
||||||
|
import org.geysermc.connector.ping.IGeyserPingPassthrough;
|
||||||
|
import org.spongepowered.api.MinecraftVersion;
|
||||||
|
import org.spongepowered.api.Sponge;
|
||||||
|
import org.spongepowered.api.event.SpongeEventFactory;
|
||||||
|
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 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() {
|
||||||
|
// come on Sponge, this is in commons, why not expose it :(
|
||||||
|
ClientPingServerEvent event;
|
||||||
|
try {
|
||||||
|
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, STATUS_CLIENT, (ClientPingServerEvent.Response) response);
|
||||||
|
} catch (ReflectiveOperationException e) {
|
||||||
|
throw new RuntimeException(e);
|
||||||
|
}
|
||||||
|
Sponge.getEventManager().post(event);
|
||||||
|
GeyserPingInfo geyserPingInfo = new GeyserPingInfo(
|
||||||
|
event.getResponse().getDescription().toPlain(),
|
||||||
|
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 static final InetSocketAddress FAKE_REMOTE = new InetSocketAddress(Inet4Address.getLoopbackAddress(), 69);
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public InetSocketAddress getAddress() {
|
||||||
|
return FAKE_REMOTE;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public MinecraftVersion getVersion() {
|
||||||
|
return Sponge.getPlatform().getMinecraftVersion();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Optional<InetSocketAddress> getVirtualHost() {
|
||||||
|
return Optional.empty();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -30,9 +30,12 @@ import ninja.leaping.configurate.ConfigurationNode;
|
||||||
import ninja.leaping.configurate.loader.ConfigurationLoader;
|
import ninja.leaping.configurate.loader.ConfigurationLoader;
|
||||||
import ninja.leaping.configurate.yaml.YAMLConfigurationLoader;
|
import ninja.leaping.configurate.yaml.YAMLConfigurationLoader;
|
||||||
import org.geysermc.common.PlatformType;
|
import org.geysermc.common.PlatformType;
|
||||||
import org.geysermc.common.bootstrap.IGeyserBootstrap;
|
import org.geysermc.connector.GeyserConfiguration;
|
||||||
import org.geysermc.connector.GeyserConnector;
|
import org.geysermc.connector.GeyserConnector;
|
||||||
|
import org.geysermc.connector.bootstrap.GeyserBootstrap;
|
||||||
import org.geysermc.connector.command.CommandManager;
|
import org.geysermc.connector.command.CommandManager;
|
||||||
|
import org.geysermc.connector.ping.GeyserLegacyPingPassthrough;
|
||||||
|
import org.geysermc.connector.ping.IGeyserPingPassthrough;
|
||||||
import org.geysermc.connector.utils.FileUtils;
|
import org.geysermc.connector.utils.FileUtils;
|
||||||
import org.geysermc.platform.sponge.command.GeyserSpongeCommandExecutor;
|
import org.geysermc.platform.sponge.command.GeyserSpongeCommandExecutor;
|
||||||
import org.geysermc.platform.sponge.command.GeyserSpongeCommandManager;
|
import org.geysermc.platform.sponge.command.GeyserSpongeCommandManager;
|
||||||
|
@ -50,7 +53,7 @@ import java.net.InetSocketAddress;
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
|
|
||||||
@Plugin(id = "geyser", name = GeyserConnector.NAME + "-Sponge", version = GeyserConnector.VERSION, url = "https://geysermc.org", authors = "GeyserMC")
|
@Plugin(id = "geyser", name = GeyserConnector.NAME + "-Sponge", version = GeyserConnector.VERSION, url = "https://geysermc.org", authors = "GeyserMC")
|
||||||
public class GeyserSpongePlugin implements IGeyserBootstrap {
|
public class GeyserSpongePlugin implements GeyserBootstrap {
|
||||||
|
|
||||||
@Inject
|
@Inject
|
||||||
private Logger logger;
|
private Logger logger;
|
||||||
|
@ -62,6 +65,7 @@ public class GeyserSpongePlugin implements IGeyserBootstrap {
|
||||||
private GeyserSpongeCommandManager geyserCommandManager;
|
private GeyserSpongeCommandManager geyserCommandManager;
|
||||||
private GeyserSpongeConfiguration geyserConfig;
|
private GeyserSpongeConfiguration geyserConfig;
|
||||||
private GeyserSpongeLogger geyserLogger;
|
private GeyserSpongeLogger geyserLogger;
|
||||||
|
private IGeyserPingPassthrough geyserSpongePingPassthrough;
|
||||||
|
|
||||||
private GeyserConnector connector;
|
private GeyserConnector connector;
|
||||||
|
|
||||||
|
@ -97,7 +101,7 @@ public class GeyserSpongePlugin implements IGeyserBootstrap {
|
||||||
|
|
||||||
// Don't change the ip if its listening on all interfaces
|
// 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
|
// 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")) {
|
if (!javaAddr.getHostString().equals("0.0.0.0") && !javaAddr.getHostString().equals("")) {
|
||||||
serverIP.setValue("127.0.0.1");
|
serverIP.setValue("127.0.0.1");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -105,9 +109,16 @@ public class GeyserSpongePlugin implements IGeyserBootstrap {
|
||||||
}
|
}
|
||||||
|
|
||||||
this.geyserLogger = new GeyserSpongeLogger(logger, geyserConfig.isDebugMode());
|
this.geyserLogger = new GeyserSpongeLogger(logger, geyserConfig.isDebugMode());
|
||||||
|
GeyserConfiguration.checkGeyserConfiguration(geyserConfig, geyserLogger);
|
||||||
this.connector = GeyserConnector.start(PlatformType.SPONGE, this);
|
this.connector = GeyserConnector.start(PlatformType.SPONGE, this);
|
||||||
this.geyserCommandManager = new GeyserSpongeCommandManager(Sponge.getCommandManager(), connector);
|
|
||||||
|
|
||||||
|
if (geyserConfig.isLegacyPingPassthrough()) {
|
||||||
|
this.geyserSpongePingPassthrough = GeyserLegacyPingPassthrough.init(connector);
|
||||||
|
} else {
|
||||||
|
this.geyserSpongePingPassthrough = new GeyserSpongePingPassthrough();
|
||||||
|
}
|
||||||
|
|
||||||
|
this.geyserCommandManager = new GeyserSpongeCommandManager(Sponge.getCommandManager(), connector);
|
||||||
Sponge.getCommandManager().register(this, new GeyserSpongeCommandExecutor(connector), "geyser");
|
Sponge.getCommandManager().register(this, new GeyserSpongeCommandExecutor(connector), "geyser");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -131,6 +142,11 @@ public class GeyserSpongePlugin implements IGeyserBootstrap {
|
||||||
return this.geyserCommandManager;
|
return this.geyserCommandManager;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public IGeyserPingPassthrough getGeyserPingPassthrough() {
|
||||||
|
return geyserSpongePingPassthrough;
|
||||||
|
}
|
||||||
|
|
||||||
@Listener
|
@Listener
|
||||||
public void onServerStart(GameStartedServerEvent event) {
|
public void onServerStart(GameStartedServerEvent event) {
|
||||||
onEnable();
|
onEnable();
|
||||||
|
|
|
@ -81,7 +81,7 @@
|
||||||
<configuration>
|
<configuration>
|
||||||
<archive>
|
<archive>
|
||||||
<manifestEntries>
|
<manifestEntries>
|
||||||
<Main-Class>org.geysermc.platform.standalone.GeyserBootstrap</Main-Class>
|
<Main-Class>org.geysermc.platform.standalone.GeyserStandaloneBootstrap</Main-Class>
|
||||||
</manifestEntries>
|
</manifestEntries>
|
||||||
</archive>
|
</archive>
|
||||||
</configuration>
|
</configuration>
|
||||||
|
@ -119,7 +119,7 @@
|
||||||
</filters>
|
</filters>
|
||||||
<transformers>
|
<transformers>
|
||||||
<transformer implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer">
|
<transformer implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer">
|
||||||
<mainClass>org.geysermc.platform.standalone.GeyserBootstrap</mainClass>
|
<mainClass>org.geysermc.platform.standalone.GeyserStandaloneBootstrap</mainClass>
|
||||||
<manifestEntries>
|
<manifestEntries>
|
||||||
<Multi-Release>true</Multi-Release>
|
<Multi-Release>true</Multi-Release>
|
||||||
</manifestEntries>
|
</manifestEntries>
|
||||||
|
|
|
@ -26,45 +26,52 @@
|
||||||
package org.geysermc.platform.standalone;
|
package org.geysermc.platform.standalone;
|
||||||
|
|
||||||
import org.geysermc.common.PlatformType;
|
import org.geysermc.common.PlatformType;
|
||||||
import org.geysermc.common.bootstrap.IGeyserBootstrap;
|
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.GeyserConnector;
|
||||||
import org.geysermc.connector.command.CommandManager;
|
import org.geysermc.connector.command.CommandManager;
|
||||||
|
import org.geysermc.connector.ping.IGeyserPingPassthrough;
|
||||||
import org.geysermc.connector.utils.FileUtils;
|
import org.geysermc.connector.utils.FileUtils;
|
||||||
import org.geysermc.platform.standalone.command.GeyserCommandManager;
|
import org.geysermc.platform.standalone.command.GeyserCommandManager;
|
||||||
import org.geysermc.platform.standalone.console.GeyserLogger;
|
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
|
|
||||||
public class GeyserBootstrap implements IGeyserBootstrap {
|
public class GeyserStandaloneBootstrap implements GeyserBootstrap {
|
||||||
|
|
||||||
private GeyserCommandManager geyserCommandManager;
|
private GeyserCommandManager geyserCommandManager;
|
||||||
private GeyserConfiguration geyserConfig;
|
private GeyserStandaloneConfiguration geyserConfig;
|
||||||
private GeyserLogger geyserLogger;
|
private GeyserStandaloneLogger geyserLogger;
|
||||||
|
private IGeyserPingPassthrough geyserPingPassthrough;
|
||||||
|
|
||||||
private GeyserConnector connector;
|
private GeyserConnector connector;
|
||||||
|
|
||||||
public static void main(String[] args) {
|
public static void main(String[] args) {
|
||||||
new GeyserBootstrap().onEnable();
|
new GeyserStandaloneBootstrap().onEnable();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onEnable() {
|
public void onEnable() {
|
||||||
geyserLogger = new GeyserLogger();
|
geyserLogger = new GeyserStandaloneLogger();
|
||||||
|
|
||||||
LoopbackUtil.checkLoopback(geyserLogger);
|
LoopbackUtil.checkLoopback(geyserLogger);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
File configFile = FileUtils.fileOrCopiedFromResource("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, GeyserConfiguration.class);
|
geyserConfig = FileUtils.loadConfig(configFile, GeyserStandaloneConfiguration.class);
|
||||||
} catch (IOException ex) {
|
} catch (IOException ex) {
|
||||||
geyserLogger.severe("Failed to read/create config.yml! Make sure it's up to date and/or readable+writable!", ex);
|
geyserLogger.severe("Failed to read/create config.yml! Make sure it's up to date and/or readable+writable!", ex);
|
||||||
System.exit(0);
|
System.exit(0);
|
||||||
}
|
}
|
||||||
|
GeyserConfiguration.checkGeyserConfiguration(geyserConfig, geyserLogger);
|
||||||
|
|
||||||
connector = GeyserConnector.start(PlatformType.STANDALONE, this);
|
connector = GeyserConnector.start(PlatformType.STANDALONE, this);
|
||||||
geyserCommandManager = new GeyserCommandManager(connector);
|
geyserCommandManager = new GeyserCommandManager(connector);
|
||||||
|
|
||||||
|
geyserPingPassthrough = GeyserLegacyPingPassthrough.init(connector);
|
||||||
|
|
||||||
geyserLogger.start();
|
geyserLogger.start();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -80,7 +87,7 @@ public class GeyserBootstrap implements IGeyserBootstrap {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public GeyserLogger getGeyserLogger() {
|
public GeyserStandaloneLogger getGeyserLogger() {
|
||||||
return geyserLogger;
|
return geyserLogger;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -88,4 +95,9 @@ public class GeyserBootstrap implements IGeyserBootstrap {
|
||||||
public CommandManager getGeyserCommandManager() {
|
public CommandManager getGeyserCommandManager() {
|
||||||
return geyserCommandManager;
|
return geyserCommandManager;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public IGeyserPingPassthrough getGeyserPingPassthrough() {
|
||||||
|
return geyserPingPassthrough;
|
||||||
|
}
|
||||||
}
|
}
|
|
@ -29,8 +29,7 @@ import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
|
||||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||||
|
|
||||||
import lombok.Getter;
|
import lombok.Getter;
|
||||||
|
import org.geysermc.connector.GeyserConfiguration;
|
||||||
import org.geysermc.common.IGeyserConfiguration;
|
|
||||||
|
|
||||||
import java.nio.file.Path;
|
import java.nio.file.Path;
|
||||||
import java.nio.file.Paths;
|
import java.nio.file.Paths;
|
||||||
|
@ -38,7 +37,7 @@ import java.util.Map;
|
||||||
|
|
||||||
@JsonIgnoreProperties(ignoreUnknown = true)
|
@JsonIgnoreProperties(ignoreUnknown = true)
|
||||||
@Getter
|
@Getter
|
||||||
public class GeyserConfiguration implements IGeyserConfiguration {
|
public class GeyserStandaloneConfiguration implements GeyserConfiguration {
|
||||||
|
|
||||||
private BedrockConfiguration bedrock;
|
private BedrockConfiguration bedrock;
|
||||||
private RemoteConfiguration remote;
|
private RemoteConfiguration remote;
|
||||||
|
@ -48,8 +47,20 @@ public class GeyserConfiguration implements IGeyserConfiguration {
|
||||||
|
|
||||||
private Map<String, UserAuthenticationInfo> userAuths;
|
private Map<String, UserAuthenticationInfo> userAuths;
|
||||||
|
|
||||||
@JsonProperty("ping-passthrough")
|
@JsonProperty("command-suggestions")
|
||||||
private boolean pingPassthrough;
|
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")
|
@JsonProperty("max-players")
|
||||||
private int maxPlayers;
|
private int maxPlayers;
|
||||||
|
@ -63,9 +74,18 @@ public class GeyserConfiguration implements IGeyserConfiguration {
|
||||||
@JsonProperty("allow-third-party-capes")
|
@JsonProperty("allow-third-party-capes")
|
||||||
private boolean allowThirdPartyCapes;
|
private boolean allowThirdPartyCapes;
|
||||||
|
|
||||||
|
@JsonProperty("allow-third-party-ears")
|
||||||
|
private boolean allowThirdPartyEars;
|
||||||
|
|
||||||
@JsonProperty("default-locale")
|
@JsonProperty("default-locale")
|
||||||
private String defaultLocale;
|
private String defaultLocale;
|
||||||
|
|
||||||
|
@JsonProperty("cache-chunks")
|
||||||
|
private boolean cacheChunks;
|
||||||
|
|
||||||
|
@JsonProperty("above-bedrock-nether-building")
|
||||||
|
private boolean isAboveBedrockNetherBuilding;
|
||||||
|
|
||||||
private MetricsInfo metrics;
|
private MetricsInfo metrics;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -110,4 +130,7 @@ public class GeyserConfiguration implements IGeyserConfiguration {
|
||||||
@JsonProperty("uuid")
|
@JsonProperty("uuid")
|
||||||
private String uniqueId;
|
private String uniqueId;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@JsonProperty("config-version")
|
||||||
|
private int configVersion;
|
||||||
}
|
}
|
|
@ -1,29 +1,30 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (c) 2019-2020 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
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
* of this software and associated documentation files (the "Software"), to deal
|
* of this software and associated documentation files (the "Software"), to deal
|
||||||
* in the Software without restriction, including without limitation the rights
|
* in the Software without restriction, including without limitation the rights
|
||||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
* copies of the Software, and to permit persons to whom the Software is
|
* copies of the Software, and to permit persons to whom the Software is
|
||||||
* furnished to do so, subject to the following conditions:
|
* furnished to do so, subject to the following conditions:
|
||||||
*
|
*
|
||||||
* The above copyright notice and this permission notice shall be included in
|
* The above copyright notice and this permission notice shall be included in
|
||||||
* all copies or substantial portions of the Software.
|
* all copies or substantial portions of the Software.
|
||||||
*
|
*
|
||||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
* 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
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
* THE SOFTWARE.
|
* THE SOFTWARE.
|
||||||
|
*
|
||||||
|
* @author GeyserMC
|
||||||
|
* @link https://github.com/GeyserMC/Geyser
|
||||||
*
|
*
|
||||||
* @author GeyserMC
|
|
||||||
* @link https://github.com/GeyserMC/Geyser
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package org.geysermc.platform.standalone.console;
|
package org.geysermc.platform.standalone;
|
||||||
|
|
||||||
import lombok.extern.log4j.Log4j2;
|
import lombok.extern.log4j.Log4j2;
|
||||||
|
|
||||||
|
@ -31,12 +32,11 @@ import net.minecrell.terminalconsole.SimpleTerminalConsole;
|
||||||
|
|
||||||
import org.apache.logging.log4j.core.config.Configurator;
|
import org.apache.logging.log4j.core.config.Configurator;
|
||||||
import org.geysermc.common.ChatColor;
|
import org.geysermc.common.ChatColor;
|
||||||
import org.geysermc.common.logger.IGeyserLogger;
|
|
||||||
import org.geysermc.connector.GeyserConnector;
|
import org.geysermc.connector.GeyserConnector;
|
||||||
import org.geysermc.connector.command.CommandSender;
|
import org.geysermc.connector.command.CommandSender;
|
||||||
|
|
||||||
@Log4j2
|
@Log4j2
|
||||||
public class GeyserLogger extends SimpleTerminalConsole implements IGeyserLogger, CommandSender {
|
public class GeyserStandaloneLogger extends SimpleTerminalConsole implements org.geysermc.connector.GeyserLogger, CommandSender {
|
||||||
|
|
||||||
private boolean colored = true;
|
private boolean colored = true;
|
||||||
|
|
|
@ -6,14 +6,13 @@ import java.nio.file.OpenOption;
|
||||||
import java.nio.file.Paths;
|
import java.nio.file.Paths;
|
||||||
|
|
||||||
import org.geysermc.common.ChatColor;
|
import org.geysermc.common.ChatColor;
|
||||||
import org.geysermc.platform.standalone.console.GeyserLogger;
|
|
||||||
|
|
||||||
public class LoopbackUtil {
|
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 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'\"";
|
private static final String loopbackCommand = "powershell -Command \"CheckNetIsolation LoopbackExempt -a -n='Microsoft.MinecraftUWP_8wekyb3d8bbwe'\"";
|
||||||
private static final String startScript = "powershell -Command \"Start-Process 'cmd' -ArgumentList /c,%temp%/loopback_minecraft.bat -Verb runAs\"";
|
private static final String startScript = "powershell -Command \"Start-Process 'cmd' -ArgumentList /c,%temp%/loopback_minecraft.bat -Verb runAs\"";
|
||||||
|
|
||||||
public static void checkLoopback(GeyserLogger geyserLogger) {
|
public static void checkLoopback(GeyserStandaloneLogger geyserLogger) {
|
||||||
if (System.getProperty("os.name").equalsIgnoreCase("Windows 10")) {
|
if (System.getProperty("os.name").equalsIgnoreCase("Windows 10")) {
|
||||||
try {
|
try {
|
||||||
Process process = Runtime.getRuntime().exec(checkExemption);
|
Process process = Runtime.getRuntime().exec(checkExemption);
|
||||||
|
|
|
@ -33,6 +33,18 @@
|
||||||
</resource>
|
</resource>
|
||||||
</resources>
|
</resources>
|
||||||
<plugins>
|
<plugins>
|
||||||
|
<plugin>
|
||||||
|
<groupId>org.apache.maven.plugins</groupId>
|
||||||
|
<artifactId>maven-jar-plugin</artifactId>
|
||||||
|
<version>3.2.0</version>
|
||||||
|
<configuration>
|
||||||
|
<archive>
|
||||||
|
<manifestEntries>
|
||||||
|
<Main-Class>org.geysermc.platform.velocity.GeyserVelocityMain</Main-Class>
|
||||||
|
</manifestEntries>
|
||||||
|
</archive>
|
||||||
|
</configuration>
|
||||||
|
</plugin>
|
||||||
<plugin>
|
<plugin>
|
||||||
<groupId>org.apache.maven.plugins</groupId>
|
<groupId>org.apache.maven.plugins</groupId>
|
||||||
<artifactId>maven-shade-plugin</artifactId>
|
<artifactId>maven-shade-plugin</artifactId>
|
||||||
|
@ -54,14 +66,6 @@
|
||||||
</execution>
|
</execution>
|
||||||
</executions>
|
</executions>
|
||||||
<configuration>
|
<configuration>
|
||||||
<filters>
|
|
||||||
<filter>
|
|
||||||
<artifact>*:*</artifact>
|
|
||||||
<excludes>
|
|
||||||
<exclude>META-INF/*</exclude>
|
|
||||||
</excludes>
|
|
||||||
</filter>
|
|
||||||
</filters>
|
|
||||||
<artifactSet>
|
<artifactSet>
|
||||||
<excludes>
|
<excludes>
|
||||||
<exclude>com.google.code.gson:*</exclude>
|
<exclude>com.google.code.gson:*</exclude>
|
||||||
|
|
|
@ -27,17 +27,22 @@ package org.geysermc.platform.velocity;
|
||||||
|
|
||||||
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
|
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
|
||||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||||
|
import com.velocitypowered.api.plugin.PluginContainer;
|
||||||
|
import com.velocitypowered.api.proxy.ProxyServer;
|
||||||
import lombok.Getter;
|
import lombok.Getter;
|
||||||
import lombok.Setter;
|
import lombok.Setter;
|
||||||
import org.geysermc.common.IGeyserConfiguration;
|
import org.geysermc.connector.FloodgateKeyLoader;
|
||||||
|
import org.geysermc.connector.GeyserConfiguration;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
import java.nio.file.Path;
|
import java.nio.file.Path;
|
||||||
import java.nio.file.Paths;
|
import java.nio.file.Paths;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
import java.util.Optional;
|
||||||
|
|
||||||
@JsonIgnoreProperties(ignoreUnknown = true)
|
@JsonIgnoreProperties(ignoreUnknown = true)
|
||||||
@Getter
|
@Getter
|
||||||
public class GeyserVelocityConfiguration implements IGeyserConfiguration {
|
public class GeyserVelocityConfiguration implements GeyserConfiguration {
|
||||||
|
|
||||||
private BedrockConfiguration bedrock;
|
private BedrockConfiguration bedrock;
|
||||||
private RemoteConfiguration remote;
|
private RemoteConfiguration remote;
|
||||||
|
@ -47,8 +52,20 @@ public class GeyserVelocityConfiguration implements IGeyserConfiguration {
|
||||||
|
|
||||||
private Map<String, UserAuthenticationInfo> userAuths;
|
private Map<String, UserAuthenticationInfo> userAuths;
|
||||||
|
|
||||||
@JsonProperty("ping-passthrough")
|
@JsonProperty("command-suggestions")
|
||||||
private boolean pingPassthrough;
|
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")
|
@JsonProperty("max-players")
|
||||||
private int maxPlayers;
|
private int maxPlayers;
|
||||||
|
@ -62,14 +79,30 @@ public class GeyserVelocityConfiguration implements IGeyserConfiguration {
|
||||||
@JsonProperty("allow-third-party-capes")
|
@JsonProperty("allow-third-party-capes")
|
||||||
private boolean allowThirdPartyCapes;
|
private boolean allowThirdPartyCapes;
|
||||||
|
|
||||||
|
@JsonProperty("allow-third-party-ears")
|
||||||
|
private boolean allowThirdPartyEars;
|
||||||
|
|
||||||
@JsonProperty("default-locale")
|
@JsonProperty("default-locale")
|
||||||
private String defaultLocale;
|
private String defaultLocale;
|
||||||
|
|
||||||
|
@JsonProperty("cache-chunks")
|
||||||
|
private boolean cacheChunks;
|
||||||
|
|
||||||
|
@JsonProperty("above-bedrock-nether-building")
|
||||||
|
private boolean aboveBedrockNetherBuilding;
|
||||||
|
|
||||||
private MetricsInfo metrics;
|
private MetricsInfo metrics;
|
||||||
|
|
||||||
|
private Path floodgateKey;
|
||||||
|
|
||||||
|
public void loadFloodgate(GeyserVelocityPlugin plugin, ProxyServer proxyServer, File dataFolder) {
|
||||||
|
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
|
@Override
|
||||||
public Path getFloodgateKeyFile() {
|
public Path getFloodgateKeyFile() {
|
||||||
return Paths.get(floodgateKeyFile);
|
return floodgateKey;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Getter
|
@Getter
|
||||||
|
@ -112,4 +145,7 @@ public class GeyserVelocityConfiguration implements IGeyserConfiguration {
|
||||||
@JsonProperty("uuid")
|
@JsonProperty("uuid")
|
||||||
private String uniqueId;
|
private String uniqueId;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@JsonProperty("config-version")
|
||||||
|
private int configVersion;
|
||||||
}
|
}
|
||||||
|
|
|
@ -27,11 +27,11 @@ package org.geysermc.platform.velocity;
|
||||||
|
|
||||||
import lombok.AllArgsConstructor;
|
import lombok.AllArgsConstructor;
|
||||||
|
|
||||||
import org.geysermc.common.logger.IGeyserLogger;
|
import org.geysermc.connector.GeyserLogger;
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
|
|
||||||
@AllArgsConstructor
|
@AllArgsConstructor
|
||||||
public class GeyserVelocityLogger implements IGeyserLogger {
|
public class GeyserVelocityLogger implements GeyserLogger {
|
||||||
|
|
||||||
private Logger logger;
|
private Logger logger;
|
||||||
private boolean debugMode;
|
private boolean debugMode;
|
||||||
|
|
|
@ -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.velocity;
|
||||||
|
|
||||||
|
import org.geysermc.common.main.IGeyserMain;
|
||||||
|
|
||||||
|
public class GeyserVelocityMain extends IGeyserMain {
|
||||||
|
|
||||||
|
public static void main(String[] args) {
|
||||||
|
new GeyserVelocityMain().displayMessage();
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getPluginType() {
|
||||||
|
return "Velocity";
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getPluginFolder() {
|
||||||
|
return "plugins";
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,98 @@
|
||||||
|
/*
|
||||||
|
* 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.velocity;
|
||||||
|
|
||||||
|
import com.velocitypowered.api.event.proxy.ProxyPingEvent;
|
||||||
|
import com.velocitypowered.api.network.ProtocolVersion;
|
||||||
|
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.common.ping.GeyserPingInfo;
|
||||||
|
import org.geysermc.connector.ping.IGeyserPingPassthrough;
|
||||||
|
|
||||||
|
import java.net.Inet4Address;
|
||||||
|
import java.net.InetSocketAddress;
|
||||||
|
import java.util.Optional;
|
||||||
|
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() {
|
||||||
|
ProxyPingEvent event;
|
||||||
|
try {
|
||||||
|
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.INSTANCE.serialize(event.getPing().getDescription(), '§'),
|
||||||
|
event.getPing().getPlayers().orElseThrow(IllegalStateException::new).getOnline(),
|
||||||
|
event.getPing().getPlayers().orElseThrow(IllegalStateException::new).getMax()
|
||||||
|
);
|
||||||
|
event.getPing().getPlayers().get().getSample().forEach(player -> {
|
||||||
|
geyserPingInfo.addPlayer(player.getName());
|
||||||
|
});
|
||||||
|
return geyserPingInfo;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static class GeyserInboundConnection implements InboundConnection {
|
||||||
|
|
||||||
|
private static final InetSocketAddress FAKE_REMOTE = new InetSocketAddress(Inet4Address.getLoopbackAddress(), 69);
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public InetSocketAddress getRemoteAddress() {
|
||||||
|
return FAKE_REMOTE;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Optional<InetSocketAddress> getVirtualHost() {
|
||||||
|
return Optional.empty();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isActive() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ProtocolVersion getProtocolVersion() {
|
||||||
|
return ProtocolVersion.MAXIMUM_VERSION;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -35,8 +35,11 @@ import com.velocitypowered.api.plugin.Plugin;
|
||||||
|
|
||||||
import com.velocitypowered.api.proxy.ProxyServer;
|
import com.velocitypowered.api.proxy.ProxyServer;
|
||||||
import org.geysermc.common.PlatformType;
|
import org.geysermc.common.PlatformType;
|
||||||
import org.geysermc.common.bootstrap.IGeyserBootstrap;
|
import org.geysermc.connector.GeyserConfiguration;
|
||||||
import org.geysermc.connector.GeyserConnector;
|
import org.geysermc.connector.GeyserConnector;
|
||||||
|
import org.geysermc.connector.bootstrap.GeyserBootstrap;
|
||||||
|
import org.geysermc.connector.ping.GeyserLegacyPingPassthrough;
|
||||||
|
import org.geysermc.connector.ping.IGeyserPingPassthrough;
|
||||||
import org.geysermc.connector.utils.FileUtils;
|
import org.geysermc.connector.utils.FileUtils;
|
||||||
import org.geysermc.platform.velocity.command.GeyserVelocityCommandExecutor;
|
import org.geysermc.platform.velocity.command.GeyserVelocityCommandExecutor;
|
||||||
import org.geysermc.platform.velocity.command.GeyserVelocityCommandManager;
|
import org.geysermc.platform.velocity.command.GeyserVelocityCommandManager;
|
||||||
|
@ -48,13 +51,13 @@ import java.net.InetSocketAddress;
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
|
|
||||||
@Plugin(id = "geyser", name = GeyserConnector.NAME + "-Velocity", version = GeyserConnector.VERSION, url = "https://geysermc.org", authors = "GeyserMC")
|
@Plugin(id = "geyser", name = GeyserConnector.NAME + "-Velocity", version = GeyserConnector.VERSION, url = "https://geysermc.org", authors = "GeyserMC")
|
||||||
public class GeyserVelocityPlugin implements IGeyserBootstrap {
|
public class GeyserVelocityPlugin implements GeyserBootstrap {
|
||||||
|
|
||||||
@Inject
|
@Inject
|
||||||
private Logger logger;
|
private Logger logger;
|
||||||
|
|
||||||
@Inject
|
@Inject
|
||||||
private ProxyServer server;
|
private ProxyServer proxyServer;
|
||||||
|
|
||||||
@Inject
|
@Inject
|
||||||
private CommandManager commandManager;
|
private CommandManager commandManager;
|
||||||
|
@ -62,13 +65,15 @@ public class GeyserVelocityPlugin implements IGeyserBootstrap {
|
||||||
private GeyserVelocityCommandManager geyserCommandManager;
|
private GeyserVelocityCommandManager geyserCommandManager;
|
||||||
private GeyserVelocityConfiguration geyserConfig;
|
private GeyserVelocityConfiguration geyserConfig;
|
||||||
private GeyserVelocityLogger geyserLogger;
|
private GeyserVelocityLogger geyserLogger;
|
||||||
|
private IGeyserPingPassthrough geyserPingPassthrough;
|
||||||
|
|
||||||
private GeyserConnector connector;
|
private GeyserConnector connector;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onEnable() {
|
public void onEnable() {
|
||||||
|
File configDir = new File("plugins/" + GeyserConnector.NAME + "-Velocity/");
|
||||||
|
|
||||||
try {
|
try {
|
||||||
File configDir = new File("plugins/" + GeyserConnector.NAME + "-Velocity/");
|
|
||||||
if (!configDir.exists())
|
if (!configDir.exists())
|
||||||
configDir.mkdir();
|
configDir.mkdir();
|
||||||
File configFile = FileUtils.fileOrCopiedFromResource(new File(configDir, "config.yml"), "config.yml", (x) -> x.replaceAll("generateduuid", UUID.randomUUID().toString()));
|
File configFile = FileUtils.fileOrCopiedFromResource(new File(configDir, "config.yml"), "config.yml", (x) -> x.replaceAll("generateduuid", UUID.randomUUID().toString()));
|
||||||
|
@ -78,21 +83,30 @@ public class GeyserVelocityPlugin implements IGeyserBootstrap {
|
||||||
ex.printStackTrace();
|
ex.printStackTrace();
|
||||||
}
|
}
|
||||||
|
|
||||||
InetSocketAddress javaAddr = server.getBoundAddress();
|
InetSocketAddress javaAddr = proxyServer.getBoundAddress();
|
||||||
|
|
||||||
// Don't change the ip if its listening on all interfaces
|
// 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
|
// 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")) {
|
if (!javaAddr.getHostString().equals("0.0.0.0") && !javaAddr.getHostString().equals("")) {
|
||||||
geyserConfig.getRemote().setAddress(javaAddr.getHostString());
|
geyserConfig.getRemote().setAddress(javaAddr.getHostString());
|
||||||
}
|
}
|
||||||
|
|
||||||
geyserConfig.getRemote().setPort(javaAddr.getPort());
|
geyserConfig.getRemote().setPort(javaAddr.getPort());
|
||||||
|
|
||||||
this.geyserLogger = new GeyserVelocityLogger(logger, geyserConfig.isDebugMode());
|
this.geyserLogger = new GeyserVelocityLogger(logger, geyserConfig.isDebugMode());
|
||||||
|
GeyserConfiguration.checkGeyserConfiguration(geyserConfig, geyserLogger);
|
||||||
|
|
||||||
|
geyserConfig.loadFloodgate(this, proxyServer, configDir);
|
||||||
|
|
||||||
this.connector = GeyserConnector.start(PlatformType.VELOCITY, this);
|
this.connector = GeyserConnector.start(PlatformType.VELOCITY, this);
|
||||||
|
|
||||||
this.geyserCommandManager = new GeyserVelocityCommandManager(connector);
|
this.geyserCommandManager = new GeyserVelocityCommandManager(connector);
|
||||||
this.commandManager.register(new GeyserVelocityCommandExecutor(connector), "geyser");
|
this.commandManager.register(new GeyserVelocityCommandExecutor(connector), "geyser");
|
||||||
|
if (geyserConfig.isLegacyPingPassthrough()) {
|
||||||
|
this.geyserPingPassthrough = GeyserLegacyPingPassthrough.init(connector);
|
||||||
|
} else {
|
||||||
|
this.geyserPingPassthrough = new GeyserVelocityPingPassthrough(proxyServer);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -115,6 +129,11 @@ public class GeyserVelocityPlugin implements IGeyserBootstrap {
|
||||||
return this.geyserCommandManager;
|
return this.geyserCommandManager;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public IGeyserPingPassthrough getGeyserPingPassthrough() {
|
||||||
|
return geyserPingPassthrough;
|
||||||
|
}
|
||||||
|
|
||||||
@Subscribe
|
@Subscribe
|
||||||
public void onInit(ProxyInitializeEvent event) {
|
public void onInit(ProxyInitializeEvent event) {
|
||||||
onEnable();
|
onEnable();
|
||||||
|
|
|
@ -1,87 +0,0 @@
|
||||||
/*
|
|
||||||
* 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;
|
|
||||||
|
|
||||||
import java.nio.file.Path;
|
|
||||||
import java.util.Map;
|
|
||||||
|
|
||||||
public interface IGeyserConfiguration {
|
|
||||||
|
|
||||||
IBedrockConfiguration getBedrock();
|
|
||||||
|
|
||||||
IRemoteConfiguration getRemote();
|
|
||||||
|
|
||||||
Map<String, ? extends IUserAuthenticationInfo> getUserAuths();
|
|
||||||
|
|
||||||
boolean isPingPassthrough();
|
|
||||||
|
|
||||||
int getMaxPlayers();
|
|
||||||
|
|
||||||
boolean isDebugMode();
|
|
||||||
|
|
||||||
int getGeneralThreadPool();
|
|
||||||
|
|
||||||
boolean isAllowThirdPartyCapes();
|
|
||||||
|
|
||||||
String getDefaultLocale();
|
|
||||||
|
|
||||||
Path getFloodgateKeyFile();
|
|
||||||
|
|
||||||
IMetricsInfo getMetrics();
|
|
||||||
|
|
||||||
interface IBedrockConfiguration {
|
|
||||||
|
|
||||||
String getAddress();
|
|
||||||
|
|
||||||
int getPort();
|
|
||||||
|
|
||||||
String getMotd1();
|
|
||||||
|
|
||||||
String getMotd2();
|
|
||||||
}
|
|
||||||
|
|
||||||
interface IRemoteConfiguration {
|
|
||||||
|
|
||||||
String getAddress();
|
|
||||||
|
|
||||||
int getPort();
|
|
||||||
|
|
||||||
String getAuthType();
|
|
||||||
}
|
|
||||||
|
|
||||||
interface IUserAuthenticationInfo {
|
|
||||||
String getEmail();
|
|
||||||
|
|
||||||
String getPassword();
|
|
||||||
}
|
|
||||||
|
|
||||||
interface IMetricsInfo {
|
|
||||||
|
|
||||||
boolean isEnabled();
|
|
||||||
|
|
||||||
String getUniqueId();
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,64 +0,0 @@
|
||||||
/*
|
|
||||||
* 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.bootstrap;
|
|
||||||
|
|
||||||
import org.geysermc.common.IGeyserConfiguration;
|
|
||||||
import org.geysermc.common.command.ICommandManager;
|
|
||||||
import org.geysermc.common.logger.IGeyserLogger;
|
|
||||||
|
|
||||||
public interface IGeyserBootstrap {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Called when the GeyserBootstrap is enabled
|
|
||||||
*/
|
|
||||||
void onEnable();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Called when the GeyserBootstrap is disabled
|
|
||||||
*/
|
|
||||||
void onDisable();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the current GeyserConfig
|
|
||||||
*
|
|
||||||
* @return The current GeyserConfig
|
|
||||||
*/
|
|
||||||
IGeyserConfiguration getGeyserConfig();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the current GeyserLogger
|
|
||||||
*
|
|
||||||
* @return The current GeyserLogger
|
|
||||||
*/
|
|
||||||
IGeyserLogger getGeyserLogger();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the current GeyserCommandManager
|
|
||||||
*
|
|
||||||
* @return The current GeyserCommandManager
|
|
||||||
*/
|
|
||||||
ICommandManager getGeyserCommandManager();
|
|
||||||
}
|
|
|
@ -1,81 +0,0 @@
|
||||||
/*
|
|
||||||
* 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.logger;
|
|
||||||
|
|
||||||
public interface IGeyserLogger {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Logs a severe message to console
|
|
||||||
*
|
|
||||||
* @param message the message to log
|
|
||||||
*/
|
|
||||||
void severe(String message);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Logs a severe message and an exception to console
|
|
||||||
*/
|
|
||||||
void severe(String message, Throwable error);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Logs an error message to console
|
|
||||||
*
|
|
||||||
* @param message the message to log
|
|
||||||
*/
|
|
||||||
void error(String message);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Logs an error message and an exception to console
|
|
||||||
*/
|
|
||||||
void error(String message, Throwable error);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Logs a warning message to console
|
|
||||||
*
|
|
||||||
* @param message the message to log
|
|
||||||
*/
|
|
||||||
void warning(String message);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Logs an info message to console
|
|
||||||
*
|
|
||||||
* @param message the message to log
|
|
||||||
*/
|
|
||||||
void info(String message);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Logs a debug message to console
|
|
||||||
*
|
|
||||||
* @param message the message to log
|
|
||||||
*/
|
|
||||||
void debug(String message);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Sets if the logger should print debug messages
|
|
||||||
*
|
|
||||||
* @param debug if the logger should print debug messages
|
|
||||||
*/
|
|
||||||
void setDebug(boolean debug);
|
|
||||||
}
|
|
|
@ -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";
|
||||||
|
}
|
||||||
|
}
|
|
@ -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);
|
||||||
|
}
|
||||||
|
}
|
|
@ -30,24 +30,39 @@ import com.fasterxml.jackson.annotation.JsonEnumDefaultValue;
|
||||||
public enum DeviceOS {
|
public enum DeviceOS {
|
||||||
|
|
||||||
@JsonEnumDefaultValue
|
@JsonEnumDefaultValue
|
||||||
UNKNOWN,
|
UNKNOWN("Unknown"),
|
||||||
ANDROID,
|
ANDROID("Android"),
|
||||||
IOS,
|
IOS("iOS"),
|
||||||
OSX,
|
OSX("macOS"),
|
||||||
FIREOS,
|
FIREOS("FireOS"),
|
||||||
GEARVR,
|
GEARVR("Gear VR"),
|
||||||
HOLOLENS,
|
HOLOLENS("Hololens"),
|
||||||
WIN10,
|
WIN10("Windows 10"),
|
||||||
WIN32,
|
WIN32("Windows"),
|
||||||
DEDICATED,
|
DEDICATED("Dedicated"),
|
||||||
ORBIS,
|
ORBIS("PS4"),
|
||||||
NX,
|
NX("Switch"),
|
||||||
SWITCH,
|
SWITCH("Switch"),
|
||||||
XBOX_ONE;
|
XBOX_ONE("Xbox One"),
|
||||||
|
WIN_PHONE("Windows Phone");
|
||||||
|
|
||||||
private static final DeviceOS[] VALUES = values();
|
private static final DeviceOS[] VALUES = values();
|
||||||
|
|
||||||
|
private final String displayName;
|
||||||
|
|
||||||
|
DeviceOS(final String displayName) {
|
||||||
|
this.displayName = displayName;
|
||||||
|
}
|
||||||
|
|
||||||
public static DeviceOS getById(int id) {
|
public static DeviceOS getById(int id) {
|
||||||
return id < VALUES.length ? VALUES[id] : VALUES[0];
|
return id < VALUES.length ? VALUES[id] : VALUES[0];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return friendly display name of platform.
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return displayName;
|
||||||
|
}
|
||||||
}
|
}
|
18
common/src/main/resources/help.txt
Normal file
18
common/src/main/resources/help.txt
Normal file
|
@ -0,0 +1,18 @@
|
||||||
|
|
||||||
|
--------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
Oops! You attempted to run a plugin version of Geyser directly!
|
||||||
|
|
||||||
|
This jar file is a plugin for ${plugin_type}. You can run this file as a
|
||||||
|
plugin by dropping the jar file into the "${plugin_folder}" directory.
|
||||||
|
|
||||||
|
There is also a standalone version available that doesn't need to
|
||||||
|
be installed as a plugin, you can find it on our build server:
|
||||||
|
|
||||||
|
http://ci.geysermc.org/
|
||||||
|
|
||||||
|
If you need more help, you should check out our discord:
|
||||||
|
|
||||||
|
http://discord.geysermc.org/
|
||||||
|
|
||||||
|
--------------------------------------------------------------------------------
|
|
@ -91,27 +91,9 @@
|
||||||
<scope>compile</scope>
|
<scope>compile</scope>
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>com.github.steveice10</groupId>
|
<groupId>com.google.guava</groupId>
|
||||||
<artifactId>opennbt</artifactId>
|
<artifactId>guava</artifactId>
|
||||||
<version>1.4-SNAPSHOT</version>
|
<version>29.0-jre</version>
|
||||||
<scope>compile</scope>
|
|
||||||
</dependency>
|
|
||||||
<dependency>
|
|
||||||
<groupId>com.github.steveice10</groupId>
|
|
||||||
<artifactId>packetlib</artifactId>
|
|
||||||
<version>1.5-SNAPSHOT</version>
|
|
||||||
<scope>compile</scope>
|
|
||||||
<exclusions>
|
|
||||||
<exclusion>
|
|
||||||
<groupId>io.netty</groupId>
|
|
||||||
<artifactId>netty-all</artifactId>
|
|
||||||
</exclusion>
|
|
||||||
</exclusions>
|
|
||||||
</dependency>
|
|
||||||
<dependency>
|
|
||||||
<groupId>com.github.steveice10</groupId>
|
|
||||||
<artifactId>mcauthlib</artifactId>
|
|
||||||
<version>1.3-SNAPSHOT</version>
|
|
||||||
<scope>compile</scope>
|
<scope>compile</scope>
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
|
@ -121,19 +103,17 @@
|
||||||
<scope>compile</scope>
|
<scope>compile</scope>
|
||||||
<exclusions>
|
<exclusions>
|
||||||
<exclusion>
|
<exclusion>
|
||||||
<groupId>com.github.steveice10</groupId>
|
<groupId>io.netty</groupId>
|
||||||
<artifactId>opennbt</artifactId>
|
<artifactId>netty-all</artifactId>
|
||||||
</exclusion>
|
|
||||||
<exclusion>
|
|
||||||
<groupId>com.github.steveice10</groupId>
|
|
||||||
<artifactId>packetlib</artifactId>
|
|
||||||
</exclusion>
|
|
||||||
<exclusion>
|
|
||||||
<groupId>com.github.steveice10</groupId>
|
|
||||||
<artifactId>mcauthlib</artifactId>
|
|
||||||
</exclusion>
|
</exclusion>
|
||||||
</exclusions>
|
</exclusions>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>io.netty</groupId>
|
||||||
|
<artifactId>netty-resolver-dns</artifactId>
|
||||||
|
<version>4.1.43.Final</version>
|
||||||
|
<scope>compile</scope>
|
||||||
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.reflections</groupId>
|
<groupId>org.reflections</groupId>
|
||||||
<artifactId>reflections</artifactId>
|
<artifactId>reflections</artifactId>
|
||||||
|
@ -158,4 +138,83 @@
|
||||||
<scope>compile</scope>
|
<scope>compile</scope>
|
||||||
</dependency>
|
</dependency>
|
||||||
</dependencies>
|
</dependencies>
|
||||||
|
|
||||||
|
<build>
|
||||||
|
<plugins>
|
||||||
|
<plugin>
|
||||||
|
<groupId>pl.project13.maven</groupId>
|
||||||
|
<artifactId>git-commit-id-plugin</artifactId>
|
||||||
|
<version>4.0.0</version>
|
||||||
|
<executions>
|
||||||
|
<execution>
|
||||||
|
<id>get-the-git-infos</id>
|
||||||
|
<goals>
|
||||||
|
<goal>revision</goal>
|
||||||
|
</goals>
|
||||||
|
</execution>
|
||||||
|
</executions>
|
||||||
|
<configuration>
|
||||||
|
<generateGitPropertiesFile>true</generateGitPropertiesFile>
|
||||||
|
<generateGitPropertiesFilename>${project.build.outputDirectory}/git.properties</generateGitPropertiesFilename>
|
||||||
|
<format>properties</format>
|
||||||
|
<failOnNoGitDirectory>false</failOnNoGitDirectory>
|
||||||
|
<failOnUnableToExtractRepoInfo>false</failOnUnableToExtractRepoInfo>
|
||||||
|
<runOnlyOnce>false</runOnlyOnce>
|
||||||
|
<verbose>true</verbose>
|
||||||
|
<skipPoms>false</skipPoms>
|
||||||
|
<excludeProperties>
|
||||||
|
<excludeProperty>git.user.*</excludeProperty>
|
||||||
|
</excludeProperties>
|
||||||
|
<commitIdGenerationMode>flat</commitIdGenerationMode>
|
||||||
|
<gitDescribe>
|
||||||
|
<always>true</always>
|
||||||
|
</gitDescribe>
|
||||||
|
</configuration>
|
||||||
|
</plugin>
|
||||||
|
<plugin>
|
||||||
|
<groupId>com.google.code.maven-replacer-plugin</groupId>
|
||||||
|
<artifactId>replacer</artifactId>
|
||||||
|
<version>1.5.3</version>
|
||||||
|
<executions>
|
||||||
|
<execution>
|
||||||
|
<id>add-version</id>
|
||||||
|
<phase>process-sources</phase>
|
||||||
|
<goals>
|
||||||
|
<goal>replace</goal>
|
||||||
|
</goals>
|
||||||
|
<configuration>
|
||||||
|
<includes>
|
||||||
|
<include>${project.basedir}/src/main/java/org/geysermc/connector/GeyserConnector.java</include>
|
||||||
|
</includes>
|
||||||
|
<replacements>
|
||||||
|
<replacement>
|
||||||
|
<token>VERSION = ".*"</token>
|
||||||
|
<value>VERSION = "${project.version} (git-${git.branch}-${git.commit.id.abbrev})"</value>
|
||||||
|
</replacement>
|
||||||
|
</replacements>
|
||||||
|
</configuration>
|
||||||
|
</execution>
|
||||||
|
|
||||||
|
<execution>
|
||||||
|
<id>remove-version</id>
|
||||||
|
<phase>process-classes</phase>
|
||||||
|
<goals>
|
||||||
|
<goal>replace</goal>
|
||||||
|
</goals>
|
||||||
|
<configuration>
|
||||||
|
<includes>
|
||||||
|
<include>${project.basedir}/src/main/java/org/geysermc/connector/GeyserConnector.java</include>
|
||||||
|
</includes>
|
||||||
|
<replacements>
|
||||||
|
<replacement>
|
||||||
|
<token>VERSION = ".*"</token>
|
||||||
|
<value>VERSION = "DEV"</value>
|
||||||
|
</replacement>
|
||||||
|
</replacements>
|
||||||
|
</configuration>
|
||||||
|
</execution>
|
||||||
|
</executions>
|
||||||
|
</plugin>
|
||||||
|
</plugins>
|
||||||
|
</build>
|
||||||
</project>
|
</project>
|
||||||
|
|
|
@ -0,0 +1,50 @@
|
||||||
|
/*
|
||||||
|
* 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.connector;
|
||||||
|
|
||||||
|
import java.nio.file.Files;
|
||||||
|
import java.nio.file.Path;
|
||||||
|
|
||||||
|
public class FloodgateKeyLoader {
|
||||||
|
public static Path getKey(GeyserLogger logger, GeyserConfiguration config, Path floodgateKey, Object floodgate, Path floodgateFolder) {
|
||||||
|
if (!Files.exists(floodgateKey) && config.getRemote().getAuthType().equals("floodgate")) {
|
||||||
|
if (floodgate != null) {
|
||||||
|
Path autoKey = floodgateFolder.resolve("public-key.pem");
|
||||||
|
if (Files.exists(autoKey)) {
|
||||||
|
logger.info("Auto-loaded floodgate key");
|
||||||
|
floodgateKey = autoKey;
|
||||||
|
} else {
|
||||||
|
logger.error("Auth-type set to floodgate and the public key is missing!");
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
logger.error("Auth-type set to floodgate but floodgate is not installed!");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return floodgateKey;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,115 @@
|
||||||
|
/*
|
||||||
|
* 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.connector;
|
||||||
|
|
||||||
|
import java.nio.file.Path;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
public interface GeyserConfiguration {
|
||||||
|
|
||||||
|
// Modify this when you update the config
|
||||||
|
int CURRENT_CONFIG_VERSION = 3;
|
||||||
|
|
||||||
|
IBedrockConfiguration getBedrock();
|
||||||
|
|
||||||
|
IRemoteConfiguration getRemote();
|
||||||
|
|
||||||
|
Map<String, ? extends IUserAuthenticationInfo> getUserAuths();
|
||||||
|
|
||||||
|
boolean isCommandSuggestions();
|
||||||
|
|
||||||
|
boolean isPassthroughMotd();
|
||||||
|
|
||||||
|
boolean isPassthroughPlayerCounts();
|
||||||
|
|
||||||
|
boolean isLegacyPingPassthrough();
|
||||||
|
|
||||||
|
int getPingPassthroughInterval();
|
||||||
|
|
||||||
|
int getMaxPlayers();
|
||||||
|
|
||||||
|
boolean isDebugMode();
|
||||||
|
|
||||||
|
int getGeneralThreadPool();
|
||||||
|
|
||||||
|
boolean isAllowThirdPartyCapes();
|
||||||
|
|
||||||
|
boolean isAllowThirdPartyEars();
|
||||||
|
|
||||||
|
String getDefaultLocale();
|
||||||
|
|
||||||
|
Path getFloodgateKeyFile();
|
||||||
|
|
||||||
|
boolean isAboveBedrockNetherBuilding();
|
||||||
|
|
||||||
|
boolean isCacheChunks();
|
||||||
|
|
||||||
|
IMetricsInfo getMetrics();
|
||||||
|
|
||||||
|
interface IBedrockConfiguration {
|
||||||
|
|
||||||
|
String getAddress();
|
||||||
|
|
||||||
|
int getPort();
|
||||||
|
|
||||||
|
String getMotd1();
|
||||||
|
|
||||||
|
String getMotd2();
|
||||||
|
}
|
||||||
|
|
||||||
|
interface IRemoteConfiguration {
|
||||||
|
|
||||||
|
String getAddress();
|
||||||
|
|
||||||
|
int getPort();
|
||||||
|
|
||||||
|
String getAuthType();
|
||||||
|
}
|
||||||
|
|
||||||
|
interface IUserAuthenticationInfo {
|
||||||
|
String getEmail();
|
||||||
|
|
||||||
|
String getPassword();
|
||||||
|
}
|
||||||
|
|
||||||
|
interface IMetricsInfo {
|
||||||
|
|
||||||
|
boolean isEnabled();
|
||||||
|
|
||||||
|
String getUniqueId();
|
||||||
|
}
|
||||||
|
|
||||||
|
int getConfigVersion();
|
||||||
|
|
||||||
|
static void checkGeyserConfiguration(GeyserConfiguration geyserConfig, GeyserLogger geyserLogger) {
|
||||||
|
if (geyserConfig.getConfigVersion() < CURRENT_CONFIG_VERSION) {
|
||||||
|
geyserLogger.warning("Your Geyser config is out of date! Please regenerate your config when possible.");
|
||||||
|
} else if (geyserConfig.getConfigVersion() > CURRENT_CONFIG_VERSION) {
|
||||||
|
geyserLogger.warning("Your Geyser config is too new! Errors may occur.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -25,26 +25,35 @@
|
||||||
|
|
||||||
package org.geysermc.connector;
|
package org.geysermc.connector;
|
||||||
|
|
||||||
|
import com.fasterxml.jackson.databind.DeserializationFeature;
|
||||||
|
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||||
import com.nukkitx.protocol.bedrock.BedrockPacketCodec;
|
import com.nukkitx.protocol.bedrock.BedrockPacketCodec;
|
||||||
import com.nukkitx.protocol.bedrock.BedrockServer;
|
import com.nukkitx.protocol.bedrock.BedrockServer;
|
||||||
import com.nukkitx.protocol.bedrock.v390.Bedrock_v390;
|
import com.nukkitx.protocol.bedrock.v390.Bedrock_v390;
|
||||||
|
|
||||||
import lombok.Getter;
|
import lombok.Getter;
|
||||||
|
|
||||||
import org.geysermc.common.AuthType;
|
import org.geysermc.common.AuthType;
|
||||||
import org.geysermc.common.IGeyserConfiguration;
|
|
||||||
import org.geysermc.common.PlatformType;
|
import org.geysermc.common.PlatformType;
|
||||||
import org.geysermc.common.bootstrap.IGeyserBootstrap;
|
import org.geysermc.connector.bootstrap.GeyserBootstrap;
|
||||||
import org.geysermc.common.logger.IGeyserLogger;
|
|
||||||
import org.geysermc.connector.command.CommandManager;
|
import org.geysermc.connector.command.CommandManager;
|
||||||
import org.geysermc.connector.metrics.Metrics;
|
import org.geysermc.connector.metrics.Metrics;
|
||||||
import org.geysermc.connector.network.ConnectorServerEventHandler;
|
import org.geysermc.connector.network.ConnectorServerEventHandler;
|
||||||
import org.geysermc.connector.network.remote.RemoteServer;
|
import org.geysermc.connector.network.remote.RemoteServer;
|
||||||
import org.geysermc.connector.network.session.GeyserSession;
|
import org.geysermc.connector.network.session.GeyserSession;
|
||||||
import org.geysermc.connector.network.translators.Translators;
|
|
||||||
import org.geysermc.connector.thread.PingPassthroughThread;
|
|
||||||
import org.geysermc.connector.utils.ResourcePack;
|
import org.geysermc.connector.utils.ResourcePack;
|
||||||
import org.geysermc.connector.utils.Toolbox;
|
import org.geysermc.connector.network.translators.BiomeTranslator;
|
||||||
|
import org.geysermc.connector.network.translators.EntityIdentifierRegistry;
|
||||||
|
import org.geysermc.connector.network.translators.PacketTranslatorRegistry;
|
||||||
|
import org.geysermc.connector.network.translators.item.ItemRegistry;
|
||||||
|
import org.geysermc.connector.network.translators.item.ItemTranslator;
|
||||||
|
import org.geysermc.connector.network.translators.sound.SoundHandlerRegistry;
|
||||||
|
import org.geysermc.connector.network.translators.world.WorldManager;
|
||||||
|
import org.geysermc.connector.network.translators.world.block.BlockTranslator;
|
||||||
|
import org.geysermc.connector.network.translators.effect.EffectRegistry;
|
||||||
|
import org.geysermc.connector.network.translators.world.block.entity.BlockEntityTranslator;
|
||||||
|
import org.geysermc.connector.utils.DimensionUtils;
|
||||||
|
import org.geysermc.connector.utils.DockerCheck;
|
||||||
|
import org.geysermc.connector.utils.LocaleUtils;
|
||||||
|
import org.geysermc.connector.network.translators.sound.SoundRegistry;
|
||||||
|
|
||||||
import java.net.InetSocketAddress;
|
import java.net.InetSocketAddress;
|
||||||
import java.text.DecimalFormat;
|
import java.text.DecimalFormat;
|
||||||
|
@ -58,10 +67,12 @@ import java.util.concurrent.TimeUnit;
|
||||||
@Getter
|
@Getter
|
||||||
public class GeyserConnector {
|
public class GeyserConnector {
|
||||||
|
|
||||||
|
public static final ObjectMapper JSON_MAPPER = new ObjectMapper().disable(DeserializationFeature.FAIL_ON_IGNORED_PROPERTIES);
|
||||||
|
|
||||||
public static final BedrockPacketCodec BEDROCK_PACKET_CODEC = Bedrock_v390.V390_CODEC;
|
public static final BedrockPacketCodec BEDROCK_PACKET_CODEC = Bedrock_v390.V390_CODEC;
|
||||||
|
|
||||||
public static final String NAME = "Geyser";
|
public static final String NAME = "Geyser";
|
||||||
public static final String VERSION = "1.0-SNAPSHOT";
|
public static final String VERSION = "DEV"; // A fallback for running in IDEs
|
||||||
|
|
||||||
private final Map<InetSocketAddress, GeyserSession> players = new HashMap<>();
|
private final Map<InetSocketAddress, GeyserSession> players = new HashMap<>();
|
||||||
|
|
||||||
|
@ -73,23 +84,22 @@ public class GeyserConnector {
|
||||||
private boolean shuttingDown = false;
|
private boolean shuttingDown = false;
|
||||||
|
|
||||||
private final ScheduledExecutorService generalThreadPool;
|
private final ScheduledExecutorService generalThreadPool;
|
||||||
private PingPassthroughThread passthroughThread;
|
|
||||||
|
|
||||||
private BedrockServer bedrockServer;
|
private BedrockServer bedrockServer;
|
||||||
private PlatformType platformType;
|
private PlatformType platformType;
|
||||||
private IGeyserBootstrap bootstrap;
|
private GeyserBootstrap bootstrap;
|
||||||
|
|
||||||
private Metrics metrics;
|
private Metrics metrics;
|
||||||
|
|
||||||
private GeyserConnector(PlatformType platformType, IGeyserBootstrap bootstrap) {
|
private GeyserConnector(PlatformType platformType, GeyserBootstrap bootstrap) {
|
||||||
long startupTime = System.currentTimeMillis();
|
long startupTime = System.currentTimeMillis();
|
||||||
|
|
||||||
instance = this;
|
instance = this;
|
||||||
|
|
||||||
this.bootstrap = bootstrap;
|
this.bootstrap = bootstrap;
|
||||||
|
|
||||||
IGeyserLogger logger = bootstrap.getGeyserLogger();
|
GeyserLogger logger = bootstrap.getGeyserLogger();
|
||||||
IGeyserConfiguration config = bootstrap.getGeyserConfig();
|
GeyserConfiguration config = bootstrap.getGeyserConfig();
|
||||||
|
|
||||||
this.platformType = platformType;
|
this.platformType = platformType;
|
||||||
|
|
||||||
|
@ -103,16 +113,30 @@ public class GeyserConnector {
|
||||||
|
|
||||||
logger.setDebug(config.isDebugMode());
|
logger.setDebug(config.isDebugMode());
|
||||||
|
|
||||||
Translators.start();
|
|
||||||
Toolbox.init();
|
|
||||||
ResourcePack.loadPacks();
|
ResourcePack.loadPacks();
|
||||||
|
PacketTranslatorRegistry.init();
|
||||||
|
|
||||||
|
/* Initialize translators and registries */
|
||||||
|
BiomeTranslator.init();
|
||||||
|
BlockTranslator.init();
|
||||||
|
BlockEntityTranslator.init();
|
||||||
|
EffectRegistry.init();
|
||||||
|
EntityIdentifierRegistry.init();
|
||||||
|
ItemRegistry.init();
|
||||||
|
ItemTranslator.init();
|
||||||
|
LocaleUtils.init();
|
||||||
|
SoundRegistry.init();
|
||||||
|
SoundHandlerRegistry.init();
|
||||||
|
|
||||||
|
if (platformType != PlatformType.STANDALONE) {
|
||||||
|
DockerCheck.check(bootstrap);
|
||||||
|
}
|
||||||
|
|
||||||
remoteServer = new RemoteServer(config.getRemote().getAddress(), config.getRemote().getPort());
|
remoteServer = new RemoteServer(config.getRemote().getAddress(), config.getRemote().getPort());
|
||||||
authType = AuthType.getByName(config.getRemote().getAuthType());
|
authType = AuthType.getByName(config.getRemote().getAuthType());
|
||||||
|
|
||||||
passthroughThread = new PingPassthroughThread(this);
|
if (config.isAboveBedrockNetherBuilding())
|
||||||
if (config.isPingPassthrough())
|
DimensionUtils.changeBedrockNetherId(); // Apply End dimension ID workaround to Nether
|
||||||
generalThreadPool.scheduleAtFixedRate(passthroughThread, 1, 1, TimeUnit.SECONDS);
|
|
||||||
|
|
||||||
bedrockServer = new BedrockServer(new InetSocketAddress(config.getBedrock().getAddress(), config.getBedrock().getPort()));
|
bedrockServer = new BedrockServer(new InetSocketAddress(config.getBedrock().getAddress(), config.getBedrock().getPort()));
|
||||||
bedrockServer.setHandler(new ConnectorServerEventHandler(this));
|
bedrockServer.setHandler(new ConnectorServerEventHandler(this));
|
||||||
|
@ -193,7 +217,7 @@ public class GeyserConnector {
|
||||||
players.remove(player.getSocketAddress());
|
players.remove(player.getSocketAddress());
|
||||||
}
|
}
|
||||||
|
|
||||||
public static GeyserConnector start(PlatformType platformType, IGeyserBootstrap bootstrap) {
|
public static GeyserConnector start(PlatformType platformType, GeyserBootstrap bootstrap) {
|
||||||
return new GeyserConnector(platformType, bootstrap);
|
return new GeyserConnector(platformType, bootstrap);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -202,16 +226,20 @@ public class GeyserConnector {
|
||||||
bootstrap.onEnable();
|
bootstrap.onEnable();
|
||||||
}
|
}
|
||||||
|
|
||||||
public IGeyserLogger getLogger() {
|
public GeyserLogger getLogger() {
|
||||||
return bootstrap.getGeyserLogger();
|
return bootstrap.getGeyserLogger();
|
||||||
}
|
}
|
||||||
|
|
||||||
public IGeyserConfiguration getConfig() {
|
public GeyserConfiguration getConfig() {
|
||||||
return bootstrap.getGeyserConfig();
|
return bootstrap.getGeyserConfig();
|
||||||
}
|
}
|
||||||
|
|
||||||
public CommandManager getCommandManager() {
|
public CommandManager getCommandManager() {
|
||||||
return (CommandManager) bootstrap.getGeyserCommandManager();
|
return bootstrap.getGeyserCommandManager();
|
||||||
|
}
|
||||||
|
|
||||||
|
public WorldManager getWorldManager() {
|
||||||
|
return bootstrap.getWorldManager();
|
||||||
}
|
}
|
||||||
|
|
||||||
public static GeyserConnector getInstance() {
|
public static GeyserConnector getInstance() {
|
||||||
|
|
|
@ -0,0 +1,82 @@
|
||||||
|
/*
|
||||||
|
* 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.connector;
|
||||||
|
|
||||||
|
public interface GeyserLogger {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Logs a severe message to console
|
||||||
|
*
|
||||||
|
* @param message the message to log
|
||||||
|
*/
|
||||||
|
void severe(String message);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Logs a severe message and an exception to console
|
||||||
|
*/
|
||||||
|
void severe(String message, Throwable error);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Logs an error message to console
|
||||||
|
*
|
||||||
|
* @param message the message to log
|
||||||
|
*/
|
||||||
|
void error(String message);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Logs an error message and an exception to console
|
||||||
|
*/
|
||||||
|
void error(String message, Throwable error);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Logs a warning message to console
|
||||||
|
*
|
||||||
|
* @param message the message to log
|
||||||
|
*/
|
||||||
|
void warning(String message);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Logs an info message to console
|
||||||
|
*
|
||||||
|
* @param message the message to log
|
||||||
|
*/
|
||||||
|
void info(String message);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Logs a debug message to console
|
||||||
|
*
|
||||||
|
* @param message the message to log
|
||||||
|
*/
|
||||||
|
void debug(String message);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets if the logger should print debug messages
|
||||||
|
*
|
||||||
|
* @param debug if the logger should print debug messages
|
||||||
|
*/
|
||||||
|
void setDebug(boolean debug);
|
||||||
|
}
|
|
@ -0,0 +1,86 @@
|
||||||
|
/*
|
||||||
|
* 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.connector.bootstrap;
|
||||||
|
|
||||||
|
import org.geysermc.connector.ping.IGeyserPingPassthrough;
|
||||||
|
import org.geysermc.connector.GeyserConfiguration;
|
||||||
|
import org.geysermc.connector.GeyserLogger;
|
||||||
|
import org.geysermc.connector.command.CommandManager;
|
||||||
|
import org.geysermc.connector.network.translators.world.CachedChunkManager;
|
||||||
|
import org.geysermc.connector.network.translators.world.WorldManager;
|
||||||
|
|
||||||
|
public interface GeyserBootstrap {
|
||||||
|
|
||||||
|
CachedChunkManager DEFAULT_CHUNK_MANAGER = new CachedChunkManager();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Called when the GeyserBootstrap is enabled
|
||||||
|
*/
|
||||||
|
void onEnable();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Called when the GeyserBootstrap is disabled
|
||||||
|
*/
|
||||||
|
void onDisable();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the current GeyserConfiguration
|
||||||
|
*
|
||||||
|
* @return The current GeyserConfiguration
|
||||||
|
*/
|
||||||
|
GeyserConfiguration getGeyserConfig();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the current GeyserLogger
|
||||||
|
*
|
||||||
|
* @return The current GeyserLogger
|
||||||
|
*/
|
||||||
|
GeyserLogger getGeyserLogger();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the current CommandManager
|
||||||
|
*
|
||||||
|
* @return The current CommandManager
|
||||||
|
*/
|
||||||
|
CommandManager getGeyserCommandManager();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the current PingPassthrough manager
|
||||||
|
*
|
||||||
|
* @return The current PingPassthrough manager
|
||||||
|
*/
|
||||||
|
IGeyserPingPassthrough getGeyserPingPassthrough();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the current WorldManager
|
||||||
|
*
|
||||||
|
* @return the current WorldManager
|
||||||
|
*/
|
||||||
|
default WorldManager getWorldManager() {
|
||||||
|
return DEFAULT_CHUNK_MANAGER;
|
||||||
|
}
|
||||||
|
}
|
|
@ -26,7 +26,7 @@
|
||||||
package org.geysermc.connector.command;
|
package org.geysermc.connector.command;
|
||||||
|
|
||||||
import lombok.Getter;
|
import lombok.Getter;
|
||||||
import org.geysermc.common.command.ICommandManager;
|
|
||||||
import org.geysermc.connector.GeyserConnector;
|
import org.geysermc.connector.GeyserConnector;
|
||||||
import org.geysermc.connector.command.defaults.*;
|
import org.geysermc.connector.command.defaults.*;
|
||||||
|
|
||||||
|
@ -34,7 +34,7 @@ import java.util.Collections;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
public abstract class CommandManager implements ICommandManager {
|
public abstract class CommandManager {
|
||||||
|
|
||||||
@Getter
|
@Getter
|
||||||
private final Map<String, GeyserCommand> commands = Collections.synchronizedMap(new HashMap<>());
|
private final Map<String, GeyserCommand> commands = Collections.synchronizedMap(new HashMap<>());
|
||||||
|
@ -87,4 +87,12 @@ public abstract class CommandManager implements ICommandManager {
|
||||||
|
|
||||||
cmd.execute(sender, args);
|
cmd.execute(sender, args);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the description of the given command
|
||||||
|
*
|
||||||
|
* @param command Command to get the description for
|
||||||
|
* @return Command description
|
||||||
|
*/
|
||||||
|
public abstract String getDescription(String command);
|
||||||
}
|
}
|
||||||
|
|
|
@ -55,7 +55,17 @@ public class OffhandCommand extends GeyserCommand {
|
||||||
GeyserSession session = (GeyserSession) sender;
|
GeyserSession session = (GeyserSession) sender;
|
||||||
ClientPlayerActionPacket releaseItemPacket = new ClientPlayerActionPacket(PlayerAction.SWAP_HANDS, new Position(0,0,0),
|
ClientPlayerActionPacket releaseItemPacket = new ClientPlayerActionPacket(PlayerAction.SWAP_HANDS, new Position(0,0,0),
|
||||||
BlockFace.DOWN);
|
BlockFace.DOWN);
|
||||||
session.getDownstream().getSession().send(releaseItemPacket);
|
session.sendDownstreamPacket(releaseItemPacket);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// Needed for Bukkit - sender is not an instance of GeyserSession
|
||||||
|
for (GeyserSession session : connector.getPlayers().values()) {
|
||||||
|
if (sender.getName().equals(session.getPlayerEntity().getUsername())) {
|
||||||
|
ClientPlayerActionPacket releaseItemPacket = new ClientPlayerActionPacket(PlayerAction.SWAP_HANDS, new Position(0,0,0),
|
||||||
|
BlockFace.DOWN);
|
||||||
|
session.sendDownstreamPacket(releaseItemPacket);
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,50 @@
|
||||||
|
/*
|
||||||
|
* 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.connector.entity;
|
||||||
|
|
||||||
|
import com.github.steveice10.mc.protocol.data.game.entity.metadata.EntityMetadata;
|
||||||
|
import com.nukkitx.math.vector.Vector3f;
|
||||||
|
import com.nukkitx.protocol.bedrock.data.EntityFlag;
|
||||||
|
import org.geysermc.connector.entity.type.EntityType;
|
||||||
|
import org.geysermc.connector.network.session.GeyserSession;
|
||||||
|
|
||||||
|
public class AbstractArrowEntity extends Entity {
|
||||||
|
|
||||||
|
public AbstractArrowEntity(long entityId, long geyserId, EntityType entityType, Vector3f position, Vector3f motion, Vector3f rotation) {
|
||||||
|
super(entityId, geyserId, entityType, position, motion, rotation);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void updateBedrockMetadata(EntityMetadata entityMetadata, GeyserSession session) {
|
||||||
|
if (entityMetadata.getId() == 7) {
|
||||||
|
byte data = (byte) entityMetadata.getValue();
|
||||||
|
|
||||||
|
metadata.getFlags().setFlag(EntityFlag.CRITICAL, (data & 0x01) == 0x01);
|
||||||
|
}
|
||||||
|
|
||||||
|
super.updateBedrockMetadata(entityMetadata, session);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,61 @@
|
||||||
|
/*
|
||||||
|
* 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.connector.entity;
|
||||||
|
|
||||||
|
import com.github.steveice10.mc.protocol.data.game.entity.metadata.EntityMetadata;
|
||||||
|
import com.github.steveice10.mc.protocol.data.game.world.particle.Particle;
|
||||||
|
import com.nukkitx.math.vector.Vector3f;
|
||||||
|
import com.nukkitx.protocol.bedrock.data.EntityData;
|
||||||
|
import org.geysermc.connector.entity.type.EntityType;
|
||||||
|
import org.geysermc.connector.network.session.GeyserSession;
|
||||||
|
import org.geysermc.connector.network.translators.effect.EffectRegistry;
|
||||||
|
|
||||||
|
public class AreaEffectCloudEntity extends Entity {
|
||||||
|
|
||||||
|
public AreaEffectCloudEntity(long entityId, long geyserId, EntityType entityType, Vector3f position, Vector3f motion, Vector3f rotation) {
|
||||||
|
super(entityId, geyserId, entityType, position, motion, rotation);
|
||||||
|
|
||||||
|
// Without this the cloud doesn't appear,
|
||||||
|
metadata.put(EntityData.AREA_EFFECT_CLOUD_DURATION, 600);
|
||||||
|
|
||||||
|
// This disabled client side shrink of the cloud
|
||||||
|
metadata.put(EntityData.AREA_EFFECT_CLOUD_RADIUS_PER_TICK, 0.0f);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void updateBedrockMetadata(EntityMetadata entityMetadata, GeyserSession session) {
|
||||||
|
if (entityMetadata.getId() == 7) {
|
||||||
|
metadata.put(EntityData.AREA_EFFECT_CLOUD_RADIUS, (float) entityMetadata.getValue());
|
||||||
|
metadata.put(EntityData.BOUNDING_BOX_WIDTH, 2.0f * (float) entityMetadata.getValue());
|
||||||
|
} else if (entityMetadata.getId() == 10) {
|
||||||
|
Particle particle = (Particle) entityMetadata.getValue();
|
||||||
|
metadata.put(EntityData.AREA_EFFECT_CLOUD_PARTICLE_ID, EffectRegistry.getParticleString(particle.getType()));
|
||||||
|
} else if (entityMetadata.getId() == 8) {
|
||||||
|
metadata.put(EntityData.POTION_COLOR, entityMetadata.getValue());
|
||||||
|
}
|
||||||
|
super.updateBedrockMetadata(entityMetadata, session);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,138 @@
|
||||||
|
/*
|
||||||
|
* 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.connector.entity;
|
||||||
|
|
||||||
|
import com.github.steveice10.mc.protocol.data.game.entity.metadata.EntityMetadata;
|
||||||
|
import com.nukkitx.math.vector.Vector3f;
|
||||||
|
import com.nukkitx.protocol.bedrock.data.EntityData;
|
||||||
|
import org.geysermc.connector.entity.type.EntityType;
|
||||||
|
import org.geysermc.connector.network.session.GeyserSession;
|
||||||
|
|
||||||
|
import java.util.concurrent.TimeUnit;
|
||||||
|
|
||||||
|
public class BoatEntity extends Entity {
|
||||||
|
|
||||||
|
private boolean isPaddlingLeft;
|
||||||
|
private float paddleTimeLeft;
|
||||||
|
private boolean isPaddlingRight;
|
||||||
|
private float paddleTimeRight;
|
||||||
|
|
||||||
|
// Looks too fast and too choppy with 0.1f, which is how I believe the Microsoftian client handles it
|
||||||
|
private final float ROWING_SPEED = 0.05f;
|
||||||
|
|
||||||
|
public BoatEntity(long entityId, long geyserId, EntityType entityType, Vector3f position, Vector3f motion, Vector3f rotation) {
|
||||||
|
super(entityId, geyserId, entityType, position.add(0d, entityType.getOffset(), 0d), motion, rotation.add(0, 0, 90));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void moveAbsolute(GeyserSession session, Vector3f position, Vector3f rotation, boolean isOnGround, boolean teleported) {
|
||||||
|
// Rotation is basically only called when entering/exiting a boat.
|
||||||
|
// We don't include the rotation (y) as it causes the boat to appear sideways
|
||||||
|
super.moveAbsolute(session, position.add(0d, this.entityType.getOffset(), 0d), Vector3f.from(0, 0, rotation.getZ() + 90), isOnGround, teleported);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void moveRelative(GeyserSession session, double relX, double relY, double relZ, Vector3f rotation, boolean isOnGround) {
|
||||||
|
super.moveRelative(session, relX, relY, relZ, Vector3f.from(0, 0, rotation.getZ()), isOnGround);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void updateBedrockMetadata(EntityMetadata entityMetadata, GeyserSession session) {
|
||||||
|
|
||||||
|
// Time since last hit
|
||||||
|
if (entityMetadata.getId() == 7) {
|
||||||
|
metadata.put(EntityData.HURT_TIME, entityMetadata.getValue());
|
||||||
|
}
|
||||||
|
|
||||||
|
// Rocking direction
|
||||||
|
if (entityMetadata.getId() == 8) {
|
||||||
|
metadata.put(EntityData.HURT_DIRECTION, entityMetadata.getValue());
|
||||||
|
}
|
||||||
|
|
||||||
|
// 'Health' in Bedrock, damage taken in Java
|
||||||
|
if (entityMetadata.getId() == 9) {
|
||||||
|
// Not exactly health but it makes motion in Bedrock
|
||||||
|
metadata.put(EntityData.HEALTH, 40 - ((int) (float) entityMetadata.getValue()));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (entityMetadata.getId() == 10) {
|
||||||
|
metadata.put(EntityData.VARIANT, entityMetadata.getValue());
|
||||||
|
} else if (entityMetadata.getId() == 11) {
|
||||||
|
isPaddlingLeft = (boolean) entityMetadata.getValue();
|
||||||
|
if (!isPaddlingLeft) {
|
||||||
|
metadata.put(EntityData.PADDLE_TIME_LEFT, 0f);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
// Java sends simply "true" and "false" (is_paddling_left), Bedrock keeps sending packets as you're rowing
|
||||||
|
// This is an asynchronous method that emulates Bedrock rowing until "false" is sent.
|
||||||
|
paddleTimeLeft = 0f;
|
||||||
|
session.getConnector().getGeneralThreadPool().execute(() ->
|
||||||
|
updateLeftPaddle(session, entityMetadata)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (entityMetadata.getId() == 12) {
|
||||||
|
isPaddlingRight = (boolean) entityMetadata.getValue();
|
||||||
|
if (!isPaddlingRight) {
|
||||||
|
metadata.put(EntityData.PADDLE_TIME_RIGHT, 0f);
|
||||||
|
} else {
|
||||||
|
paddleTimeRight = 0f;
|
||||||
|
session.getConnector().getGeneralThreadPool().execute(() ->
|
||||||
|
updateRightPaddle(session, entityMetadata)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
} else if (entityMetadata.getId() == 13) {
|
||||||
|
// Possibly - I don't think this does anything?
|
||||||
|
metadata.put(EntityData.BOAT_BUBBLE_TIME, entityMetadata.getValue());
|
||||||
|
}
|
||||||
|
|
||||||
|
super.updateBedrockMetadata(entityMetadata, session);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void updateLeftPaddle(GeyserSession session, EntityMetadata entityMetadata) {
|
||||||
|
if (isPaddlingLeft) {
|
||||||
|
paddleTimeLeft += ROWING_SPEED;
|
||||||
|
metadata.put(EntityData.PADDLE_TIME_LEFT, paddleTimeLeft);
|
||||||
|
super.updateBedrockMetadata(entityMetadata, session);
|
||||||
|
session.getConnector().getGeneralThreadPool().schedule(() ->
|
||||||
|
updateLeftPaddle(session, entityMetadata),
|
||||||
|
100,
|
||||||
|
TimeUnit.MILLISECONDS
|
||||||
|
);
|
||||||
|
}}
|
||||||
|
|
||||||
|
public void updateRightPaddle(GeyserSession session, EntityMetadata entityMetadata) {
|
||||||
|
if (isPaddlingRight) {
|
||||||
|
paddleTimeRight += ROWING_SPEED;
|
||||||
|
metadata.put(EntityData.PADDLE_TIME_RIGHT, paddleTimeRight);
|
||||||
|
super.updateBedrockMetadata(entityMetadata, session);
|
||||||
|
session.getConnector().getGeneralThreadPool().schedule(() ->
|
||||||
|
updateRightPaddle(session, entityMetadata),
|
||||||
|
100,
|
||||||
|
TimeUnit.MILLISECONDS
|
||||||
|
);
|
||||||
|
}}
|
||||||
|
}
|
|
@ -31,7 +31,6 @@ import com.nukkitx.math.vector.Vector3f;
|
||||||
import com.nukkitx.math.vector.Vector3i;
|
import com.nukkitx.math.vector.Vector3i;
|
||||||
import com.nukkitx.protocol.bedrock.data.EntityData;
|
import com.nukkitx.protocol.bedrock.data.EntityData;
|
||||||
import com.nukkitx.protocol.bedrock.data.EntityFlag;
|
import com.nukkitx.protocol.bedrock.data.EntityFlag;
|
||||||
import com.nukkitx.protocol.bedrock.packet.AddEntityPacket;
|
|
||||||
import org.geysermc.connector.entity.type.EntityType;
|
import org.geysermc.connector.entity.type.EntityType;
|
||||||
import org.geysermc.connector.network.session.GeyserSession;
|
import org.geysermc.connector.network.session.GeyserSession;
|
||||||
|
|
||||||
|
@ -60,23 +59,4 @@ public class EnderCrystalEntity extends Entity {
|
||||||
}
|
}
|
||||||
super.updateBedrockMetadata(entityMetadata, session);
|
super.updateBedrockMetadata(entityMetadata, session);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public void spawnEntity(GeyserSession session) {
|
|
||||||
AddEntityPacket addEntityPacket = new AddEntityPacket();
|
|
||||||
// Not end crystal but ender crystal
|
|
||||||
addEntityPacket.setIdentifier("minecraft:ender_crystal");
|
|
||||||
addEntityPacket.setRuntimeEntityId(geyserId);
|
|
||||||
addEntityPacket.setUniqueEntityId(geyserId);
|
|
||||||
addEntityPacket.setPosition(position);
|
|
||||||
addEntityPacket.setMotion(motion);
|
|
||||||
addEntityPacket.setRotation(getBedrockRotation());
|
|
||||||
addEntityPacket.setEntityType(entityType.getType());
|
|
||||||
addEntityPacket.getMetadata().putAll(metadata);
|
|
||||||
|
|
||||||
valid = true;
|
|
||||||
session.getUpstream().sendPacket(addEntityPacket);
|
|
||||||
|
|
||||||
session.getConnector().getLogger().debug("Spawned entity " + entityType + " at location " + position + " with id " + geyserId + " (java id " + entityId + ")");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -27,32 +27,40 @@ package org.geysermc.connector.entity;
|
||||||
|
|
||||||
import com.github.steveice10.mc.protocol.data.game.entity.metadata.EntityMetadata;
|
import com.github.steveice10.mc.protocol.data.game.entity.metadata.EntityMetadata;
|
||||||
import com.github.steveice10.mc.protocol.data.game.entity.metadata.MetadataType;
|
import com.github.steveice10.mc.protocol.data.game.entity.metadata.MetadataType;
|
||||||
|
import com.github.steveice10.mc.protocol.data.game.entity.metadata.Pose;
|
||||||
import com.github.steveice10.mc.protocol.data.game.entity.metadata.Position;
|
import com.github.steveice10.mc.protocol.data.game.entity.metadata.Position;
|
||||||
import com.github.steveice10.mc.protocol.data.game.entity.player.Hand;
|
import com.github.steveice10.mc.protocol.data.game.entity.player.Hand;
|
||||||
import com.github.steveice10.mc.protocol.data.game.entity.player.PlayerAction;
|
import com.github.steveice10.mc.protocol.data.game.entity.player.PlayerAction;
|
||||||
import com.github.steveice10.mc.protocol.data.game.world.block.BlockFace;
|
import com.github.steveice10.mc.protocol.data.game.world.block.BlockFace;
|
||||||
|
import com.github.steveice10.mc.protocol.data.game.world.block.BlockState;
|
||||||
import com.github.steveice10.mc.protocol.data.message.TextMessage;
|
import com.github.steveice10.mc.protocol.data.message.TextMessage;
|
||||||
|
import com.github.steveice10.mc.protocol.data.message.TranslationMessage;
|
||||||
import com.github.steveice10.mc.protocol.packet.ingame.client.player.ClientPlayerActionPacket;
|
import com.github.steveice10.mc.protocol.packet.ingame.client.player.ClientPlayerActionPacket;
|
||||||
import com.github.steveice10.mc.protocol.packet.ingame.client.player.ClientPlayerUseItemPacket;
|
import com.github.steveice10.mc.protocol.packet.ingame.client.player.ClientPlayerUseItemPacket;
|
||||||
import com.nukkitx.math.vector.Vector3f;
|
import com.nukkitx.math.vector.Vector3f;
|
||||||
import com.nukkitx.protocol.bedrock.data.*;
|
import com.nukkitx.math.vector.Vector3i;
|
||||||
|
import com.nukkitx.protocol.bedrock.data.EntityData;
|
||||||
|
import com.nukkitx.protocol.bedrock.data.EntityDataMap;
|
||||||
|
import com.nukkitx.protocol.bedrock.data.EntityFlag;
|
||||||
|
import com.nukkitx.protocol.bedrock.data.EntityFlags;
|
||||||
import com.nukkitx.protocol.bedrock.packet.*;
|
import com.nukkitx.protocol.bedrock.packet.*;
|
||||||
|
|
||||||
import it.unimi.dsi.fastutil.longs.LongOpenHashSet;
|
import it.unimi.dsi.fastutil.longs.LongOpenHashSet;
|
||||||
import it.unimi.dsi.fastutil.longs.LongSet;
|
|
||||||
|
|
||||||
import lombok.Getter;
|
import lombok.Getter;
|
||||||
import lombok.Setter;
|
import lombok.Setter;
|
||||||
|
|
||||||
import org.geysermc.connector.entity.attribute.Attribute;
|
import org.geysermc.connector.entity.attribute.Attribute;
|
||||||
import org.geysermc.connector.entity.attribute.AttributeType;
|
import org.geysermc.connector.entity.attribute.AttributeType;
|
||||||
|
import org.geysermc.connector.entity.living.ArmorStandEntity;
|
||||||
import org.geysermc.connector.entity.type.EntityType;
|
import org.geysermc.connector.entity.type.EntityType;
|
||||||
import org.geysermc.connector.network.session.GeyserSession;
|
import org.geysermc.connector.network.session.GeyserSession;
|
||||||
import org.geysermc.connector.network.translators.item.ItemTranslator;
|
import org.geysermc.connector.network.translators.item.ItemRegistry;
|
||||||
import org.geysermc.connector.utils.AttributeUtils;
|
import org.geysermc.connector.utils.AttributeUtils;
|
||||||
|
import org.geysermc.connector.utils.ChunkUtils;
|
||||||
import org.geysermc.connector.utils.MessageUtils;
|
import org.geysermc.connector.utils.MessageUtils;
|
||||||
|
|
||||||
import java.util.*;
|
import java.util.ArrayList;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
@Getter
|
@Getter
|
||||||
@Setter
|
@Setter
|
||||||
|
@ -76,7 +84,7 @@ public class Entity {
|
||||||
|
|
||||||
protected boolean valid;
|
protected boolean valid;
|
||||||
|
|
||||||
protected LongSet passengers = new LongOpenHashSet();
|
protected LongOpenHashSet passengers = new LongOpenHashSet();
|
||||||
protected Map<AttributeType, Attribute> attributes = new HashMap<>();
|
protected Map<AttributeType, Attribute> attributes = new HashMap<>();
|
||||||
protected EntityDataMap metadata = new EntityDataMap();
|
protected EntityDataMap metadata = new EntityDataMap();
|
||||||
|
|
||||||
|
@ -93,7 +101,8 @@ public class Entity {
|
||||||
setPosition(position);
|
setPosition(position);
|
||||||
|
|
||||||
metadata.put(EntityData.SCALE, 1f);
|
metadata.put(EntityData.SCALE, 1f);
|
||||||
metadata.put(EntityData.MAX_AIR, (short) 400);
|
metadata.put(EntityData.COLOR, 0);
|
||||||
|
metadata.put(EntityData.MAX_AIR, (short) 300);
|
||||||
metadata.put(EntityData.AIR, (short) 0);
|
metadata.put(EntityData.AIR, (short) 0);
|
||||||
metadata.put(EntityData.LEAD_HOLDER_EID, -1L);
|
metadata.put(EntityData.LEAD_HOLDER_EID, -1L);
|
||||||
metadata.put(EntityData.BOUNDING_BOX_HEIGHT, entityType.getHeight());
|
metadata.put(EntityData.BOUNDING_BOX_HEIGHT, entityType.getHeight());
|
||||||
|
@ -108,7 +117,7 @@ public class Entity {
|
||||||
|
|
||||||
public void spawnEntity(GeyserSession session) {
|
public void spawnEntity(GeyserSession session) {
|
||||||
AddEntityPacket addEntityPacket = new AddEntityPacket();
|
AddEntityPacket addEntityPacket = new AddEntityPacket();
|
||||||
addEntityPacket.setIdentifier("minecraft:" + entityType.name().toLowerCase());
|
addEntityPacket.setIdentifier(entityType.getIdentifier());
|
||||||
addEntityPacket.setRuntimeEntityId(geyserId);
|
addEntityPacket.setRuntimeEntityId(geyserId);
|
||||||
addEntityPacket.setUniqueEntityId(geyserId);
|
addEntityPacket.setUniqueEntityId(geyserId);
|
||||||
addEntityPacket.setPosition(position);
|
addEntityPacket.setPosition(position);
|
||||||
|
@ -118,7 +127,7 @@ public class Entity {
|
||||||
addEntityPacket.getMetadata().putAll(metadata);
|
addEntityPacket.getMetadata().putAll(metadata);
|
||||||
|
|
||||||
valid = true;
|
valid = true;
|
||||||
session.getUpstream().sendPacket(addEntityPacket);
|
session.sendUpstreamPacket(addEntityPacket);
|
||||||
|
|
||||||
session.getConnector().getLogger().debug("Spawned entity " + entityType + " at location " + position + " with id " + geyserId + " (java id " + entityId + ")");
|
session.getConnector().getLogger().debug("Spawned entity " + entityType + " at location " + position + " with id " + geyserId + " (java id " + entityId + ")");
|
||||||
}
|
}
|
||||||
|
@ -134,7 +143,7 @@ public class Entity {
|
||||||
|
|
||||||
RemoveEntityPacket removeEntityPacket = new RemoveEntityPacket();
|
RemoveEntityPacket removeEntityPacket = new RemoveEntityPacket();
|
||||||
removeEntityPacket.setUniqueEntityId(geyserId);
|
removeEntityPacket.setUniqueEntityId(geyserId);
|
||||||
session.getUpstream().sendPacket(removeEntityPacket);
|
session.sendUpstreamPacket(removeEntityPacket);
|
||||||
|
|
||||||
valid = false;
|
valid = false;
|
||||||
return true;
|
return true;
|
||||||
|
@ -155,14 +164,14 @@ public class Entity {
|
||||||
moveEntityPacket.setOnGround(isOnGround);
|
moveEntityPacket.setOnGround(isOnGround);
|
||||||
moveEntityPacket.setTeleported(false);
|
moveEntityPacket.setTeleported(false);
|
||||||
|
|
||||||
session.getUpstream().sendPacket(moveEntityPacket);
|
session.sendUpstreamPacket(moveEntityPacket);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void moveAbsolute(GeyserSession session, Vector3f position, float yaw, float pitch, boolean isOnGround) {
|
public void moveAbsolute(GeyserSession session, Vector3f position, float yaw, float pitch, boolean isOnGround, boolean teleported) {
|
||||||
moveAbsolute(session, position, Vector3f.from(yaw, pitch, yaw), isOnGround);
|
moveAbsolute(session, position, Vector3f.from(yaw, pitch, yaw), isOnGround, teleported);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void moveAbsolute(GeyserSession session, Vector3f position, Vector3f rotation, boolean isOnGround) {
|
public void moveAbsolute(GeyserSession session, Vector3f position, Vector3f rotation, boolean isOnGround, boolean teleported) {
|
||||||
setPosition(position);
|
setPosition(position);
|
||||||
setRotation(rotation);
|
setRotation(rotation);
|
||||||
|
|
||||||
|
@ -171,9 +180,9 @@ public class Entity {
|
||||||
moveEntityPacket.setPosition(position);
|
moveEntityPacket.setPosition(position);
|
||||||
moveEntityPacket.setRotation(getBedrockRotation());
|
moveEntityPacket.setRotation(getBedrockRotation());
|
||||||
moveEntityPacket.setOnGround(isOnGround);
|
moveEntityPacket.setOnGround(isOnGround);
|
||||||
moveEntityPacket.setTeleported(false);
|
moveEntityPacket.setTeleported(teleported);
|
||||||
|
|
||||||
session.getUpstream().sendPacket(moveEntityPacket);
|
session.sendUpstreamPacket(moveEntityPacket);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void updateBedrockAttributes(GeyserSession session) {
|
public void updateBedrockAttributes(GeyserSession session) {
|
||||||
|
@ -190,7 +199,7 @@ public class Entity {
|
||||||
UpdateAttributesPacket updateAttributesPacket = new UpdateAttributesPacket();
|
UpdateAttributesPacket updateAttributesPacket = new UpdateAttributesPacket();
|
||||||
updateAttributesPacket.setRuntimeEntityId(geyserId);
|
updateAttributesPacket.setRuntimeEntityId(geyserId);
|
||||||
updateAttributesPacket.setAttributes(attributes);
|
updateAttributesPacket.setAttributes(attributes);
|
||||||
session.getUpstream().sendPacket(updateAttributesPacket);
|
session.sendUpstreamPacket(updateAttributesPacket);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void updateBedrockMetadata(EntityMetadata entityMetadata, GeyserSession session) {
|
public void updateBedrockMetadata(EntityMetadata entityMetadata, GeyserSession session) {
|
||||||
|
@ -204,38 +213,56 @@ public class Entity {
|
||||||
metadata.getFlags().setFlag(EntityFlag.SWIMMING, (xd & 0x10) == 0x10);
|
metadata.getFlags().setFlag(EntityFlag.SWIMMING, (xd & 0x10) == 0x10);
|
||||||
metadata.getFlags().setFlag(EntityFlag.GLIDING, (xd & 0x80) == 0x80);
|
metadata.getFlags().setFlag(EntityFlag.GLIDING, (xd & 0x80) == 0x80);
|
||||||
|
|
||||||
|
if ((xd & 0x20) == 0x20) {
|
||||||
|
if (this.is(ArmorStandEntity.class)) {
|
||||||
|
metadata.put(EntityData.SCALE, 0.0f);
|
||||||
|
} else {
|
||||||
|
metadata.getFlags().setFlag(EntityFlag.INVISIBLE, true);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
metadata.getFlags().setFlag(EntityFlag.INVISIBLE, false);
|
||||||
|
}
|
||||||
|
|
||||||
// Shield code
|
// Shield code
|
||||||
if (session.getPlayerEntity().getEntityId() == entityId && metadata.getFlags().getFlag(EntityFlag.SNEAKING)) {
|
if (session.getPlayerEntity().getEntityId() == entityId && metadata.getFlags().getFlag(EntityFlag.SNEAKING)) {
|
||||||
if ((session.getInventory().getItemInHand() != null && session.getInventory().getItemInHand().getId() == ItemTranslator.SHIELD) ||
|
if ((session.getInventory().getItemInHand() != null && session.getInventory().getItemInHand().getId() == ItemRegistry.SHIELD) ||
|
||||||
(session.getInventoryCache().getPlayerInventory().getItem(45) != null && session.getInventoryCache().getPlayerInventory().getItem(45).getId() == ItemTranslator.SHIELD)) {
|
(session.getInventoryCache().getPlayerInventory().getItem(45) != null && session.getInventoryCache().getPlayerInventory().getItem(45).getId() == ItemRegistry.SHIELD)) {
|
||||||
ClientPlayerUseItemPacket useItemPacket;
|
ClientPlayerUseItemPacket useItemPacket;
|
||||||
metadata.getFlags().setFlag(EntityFlag.BLOCKING, true);
|
metadata.getFlags().setFlag(EntityFlag.BLOCKING, true);
|
||||||
if (session.getInventory().getItemInHand() != null && session.getInventory().getItemInHand().getId() == ItemTranslator.SHIELD) {
|
if (session.getInventory().getItemInHand() != null && session.getInventory().getItemInHand().getId() == ItemRegistry.SHIELD) {
|
||||||
useItemPacket = new ClientPlayerUseItemPacket(Hand.MAIN_HAND);
|
useItemPacket = new ClientPlayerUseItemPacket(Hand.MAIN_HAND);
|
||||||
}
|
}
|
||||||
// Else we just assume it's the offhand, to simplify logic and to assure the packet gets sent
|
// Else we just assume it's the offhand, to simplify logic and to assure the packet gets sent
|
||||||
else {
|
else {
|
||||||
useItemPacket = new ClientPlayerUseItemPacket(Hand.OFF_HAND);
|
useItemPacket = new ClientPlayerUseItemPacket(Hand.OFF_HAND);
|
||||||
}
|
}
|
||||||
session.getDownstream().getSession().send(useItemPacket);
|
session.sendDownstreamPacket(useItemPacket);
|
||||||
}
|
}
|
||||||
} else if (session.getPlayerEntity().getEntityId() == entityId && !metadata.getFlags().getFlag(EntityFlag.SNEAKING) && metadata.getFlags().getFlag(EntityFlag.BLOCKING)) {
|
} else if (session.getPlayerEntity().getEntityId() == entityId && !metadata.getFlags().getFlag(EntityFlag.SNEAKING) && metadata.getFlags().getFlag(EntityFlag.BLOCKING)) {
|
||||||
metadata.getFlags().setFlag(EntityFlag.BLOCKING, false);
|
metadata.getFlags().setFlag(EntityFlag.BLOCKING, false);
|
||||||
metadata.getFlags().setFlag(EntityFlag.DISABLE_BLOCKING, true);
|
metadata.getFlags().setFlag(EntityFlag.DISABLE_BLOCKING, true);
|
||||||
ClientPlayerActionPacket releaseItemPacket = new ClientPlayerActionPacket(PlayerAction.RELEASE_USE_ITEM, new Position(0,0,0), BlockFace.DOWN);
|
ClientPlayerActionPacket releaseItemPacket = new ClientPlayerActionPacket(PlayerAction.RELEASE_USE_ITEM, new Position(0, 0, 0), BlockFace.DOWN);
|
||||||
session.getDownstream().getSession().send(releaseItemPacket);
|
session.sendDownstreamPacket(releaseItemPacket);
|
||||||
}
|
}
|
||||||
// metadata.getFlags().setFlag(EntityFlag.INVISIBLE, (xd & 0x20) == 0x20);
|
}
|
||||||
if ((xd & 0x20) == 0x20)
|
break;
|
||||||
metadata.put(EntityData.SCALE, 0.0f);
|
case 1: // Air/bubbles
|
||||||
else
|
if ((int) entityMetadata.getValue() == 300) {
|
||||||
metadata.put(EntityData.SCALE, scale);
|
metadata.put(EntityData.AIR, (short) 0); // Otherwise the bubble counter remains in the UI
|
||||||
|
} else {
|
||||||
|
metadata.put(EntityData.AIR, (short) (int) entityMetadata.getValue());
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case 2: // custom name
|
case 2: // custom name
|
||||||
TextMessage name = (TextMessage) entityMetadata.getValue();
|
if (entityMetadata.getValue() instanceof TextMessage) {
|
||||||
if (name != null)
|
TextMessage name = (TextMessage) entityMetadata.getValue();
|
||||||
metadata.put(EntityData.NAMETAG, MessageUtils.getBedrockMessage(name));
|
if (name != null)
|
||||||
|
metadata.put(EntityData.NAMETAG, MessageUtils.getBedrockMessage(name));
|
||||||
|
} else if (entityMetadata.getValue() instanceof TranslationMessage) {
|
||||||
|
TranslationMessage message = (TranslationMessage) entityMetadata.getValue();
|
||||||
|
if (message != null)
|
||||||
|
metadata.put(EntityData.NAMETAG, MessageUtils.getTranslatedBedrockMessage(message, session.getClientData().getLanguageCode(), true));
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
case 3: // is custom name visible
|
case 3: // is custom name visible
|
||||||
if (!this.is(PlayerEntity.class))
|
if (!this.is(PlayerEntity.class))
|
||||||
|
@ -247,6 +274,32 @@ public class Entity {
|
||||||
case 5: // no gravity
|
case 5: // no gravity
|
||||||
metadata.getFlags().setFlag(EntityFlag.HAS_GRAVITY, !(boolean) entityMetadata.getValue());
|
metadata.getFlags().setFlag(EntityFlag.HAS_GRAVITY, !(boolean) entityMetadata.getValue());
|
||||||
break;
|
break;
|
||||||
|
case 6: // Pose change
|
||||||
|
if (entityMetadata.getValue().equals(Pose.SLEEPING)) {
|
||||||
|
metadata.getFlags().setFlag(EntityFlag.SLEEPING, true);
|
||||||
|
// Has to be a byte or it does not work
|
||||||
|
metadata.put(EntityData.CAN_START_SLEEP, (byte) 2);
|
||||||
|
if (entityId == session.getPlayerEntity().getEntityId()) {
|
||||||
|
Vector3i lastInteractionPos = session.getLastInteractionPosition();
|
||||||
|
metadata.put(EntityData.BED_RESPAWN_POS, lastInteractionPos);
|
||||||
|
if (session.getConnector().getConfig().isCacheChunks()) {
|
||||||
|
BlockState bed = session.getConnector().getWorldManager().getBlockAt(session, lastInteractionPos.getX(),
|
||||||
|
lastInteractionPos.getY(), lastInteractionPos.getZ());
|
||||||
|
// Bed has to be updated, or else player is floating in the air
|
||||||
|
ChunkUtils.updateBlock(session, bed, lastInteractionPos);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
metadata.put(EntityData.BED_RESPAWN_POS, Vector3i.from(position.getFloorX(), position.getFloorY() - 2, position.getFloorZ()));
|
||||||
|
}
|
||||||
|
metadata.put(EntityData.BOUNDING_BOX_WIDTH, 0.2f);
|
||||||
|
metadata.put(EntityData.BOUNDING_BOX_HEIGHT, 0.2f);
|
||||||
|
} else if (metadata.getFlags().getFlag(EntityFlag.SLEEPING)) {
|
||||||
|
metadata.getFlags().setFlag(EntityFlag.SLEEPING, false);
|
||||||
|
metadata.put(EntityData.BOUNDING_BOX_WIDTH, getEntityType().getWidth());
|
||||||
|
metadata.put(EntityData.BOUNDING_BOX_HEIGHT, getEntityType().getHeight());
|
||||||
|
metadata.put(EntityData.CAN_START_SLEEP, (byte) 0);
|
||||||
|
}
|
||||||
|
break;
|
||||||
case 7: // blocking
|
case 7: // blocking
|
||||||
if (entityMetadata.getType() == MetadataType.BYTE) {
|
if (entityMetadata.getType() == MetadataType.BYTE) {
|
||||||
byte xd = (byte) entityMetadata.getValue();
|
byte xd = (byte) entityMetadata.getValue();
|
||||||
|
@ -264,11 +317,12 @@ public class Entity {
|
||||||
SetEntityDataPacket entityDataPacket = new SetEntityDataPacket();
|
SetEntityDataPacket entityDataPacket = new SetEntityDataPacket();
|
||||||
entityDataPacket.setRuntimeEntityId(geyserId);
|
entityDataPacket.setRuntimeEntityId(geyserId);
|
||||||
entityDataPacket.getMetadata().putAll(metadata);
|
entityDataPacket.getMetadata().putAll(metadata);
|
||||||
session.getUpstream().sendPacket(entityDataPacket);
|
session.sendUpstreamPacket(entityDataPacket);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* x = Pitch, y = HeadYaw, z = Yaw
|
* x = Pitch, y = HeadYaw, z = Yaw
|
||||||
|
*
|
||||||
* @return the bedrock rotation
|
* @return the bedrock rotation
|
||||||
*/
|
*/
|
||||||
public Vector3f getBedrockRotation() {
|
public Vector3f getBedrockRotation() {
|
||||||
|
|
|
@ -26,7 +26,7 @@
|
||||||
package org.geysermc.connector.entity;
|
package org.geysermc.connector.entity;
|
||||||
|
|
||||||
import com.nukkitx.math.vector.Vector3f;
|
import com.nukkitx.math.vector.Vector3f;
|
||||||
import com.nukkitx.protocol.bedrock.packet.SpawnExperienceOrbPacket;
|
import com.nukkitx.protocol.bedrock.data.EntityData;
|
||||||
import org.geysermc.connector.entity.type.EntityType;
|
import org.geysermc.connector.entity.type.EntityType;
|
||||||
import org.geysermc.connector.network.session.GeyserSession;
|
import org.geysermc.connector.network.session.GeyserSession;
|
||||||
|
|
||||||
|
@ -42,11 +42,7 @@ public class ExpOrbEntity extends Entity {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void spawnEntity(GeyserSession session) {
|
public void spawnEntity(GeyserSession session) {
|
||||||
SpawnExperienceOrbPacket spawnExpOrbPacket = new SpawnExperienceOrbPacket();
|
this.metadata.put(EntityData.EXPERIENCE_VALUE, amount);
|
||||||
spawnExpOrbPacket.setPosition(position);
|
super.spawnEntity(session);
|
||||||
spawnExpOrbPacket.setAmount(amount);
|
|
||||||
|
|
||||||
valid = true;
|
|
||||||
session.getUpstream().sendPacket(spawnExpOrbPacket);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -28,7 +28,7 @@ package org.geysermc.connector.entity;
|
||||||
import com.nukkitx.math.vector.Vector3f;
|
import com.nukkitx.math.vector.Vector3f;
|
||||||
import com.nukkitx.protocol.bedrock.data.EntityData;
|
import com.nukkitx.protocol.bedrock.data.EntityData;
|
||||||
import org.geysermc.connector.entity.type.EntityType;
|
import org.geysermc.connector.entity.type.EntityType;
|
||||||
import org.geysermc.connector.network.translators.block.BlockTranslator;
|
import org.geysermc.connector.network.translators.world.block.BlockTranslator;
|
||||||
|
|
||||||
public class FallingBlockEntity extends Entity {
|
public class FallingBlockEntity extends Entity {
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,139 @@
|
||||||
|
/*
|
||||||
|
* 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.connector.entity;
|
||||||
|
|
||||||
|
import com.github.steveice10.mc.protocol.data.game.entity.metadata.EntityMetadata;
|
||||||
|
import com.github.steveice10.mc.protocol.data.game.entity.metadata.ItemStack;
|
||||||
|
import com.github.steveice10.opennbt.tag.builtin.CompoundTag;
|
||||||
|
import com.github.steveice10.opennbt.tag.builtin.ListTag;
|
||||||
|
import com.github.steveice10.opennbt.tag.builtin.Tag;
|
||||||
|
import com.nukkitx.math.vector.Vector3f;
|
||||||
|
import com.nukkitx.nbt.CompoundTagBuilder;
|
||||||
|
import com.nukkitx.protocol.bedrock.data.EntityData;
|
||||||
|
import com.nukkitx.protocol.bedrock.packet.SetEntityMotionPacket;
|
||||||
|
import org.geysermc.connector.entity.type.EntityType;
|
||||||
|
import org.geysermc.connector.network.session.GeyserSession;
|
||||||
|
import org.geysermc.connector.utils.FireworkColor;
|
||||||
|
import org.geysermc.connector.utils.MathUtils;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.OptionalInt;
|
||||||
|
|
||||||
|
public class FireworkEntity extends Entity {
|
||||||
|
|
||||||
|
public FireworkEntity(long entityId, long geyserId, EntityType entityType, Vector3f position, Vector3f motion, Vector3f rotation) {
|
||||||
|
super(entityId, geyserId, entityType, position, motion, rotation);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void updateBedrockMetadata(EntityMetadata entityMetadata, GeyserSession session) {
|
||||||
|
if (entityMetadata.getId() == 7) {
|
||||||
|
ItemStack item = (ItemStack) entityMetadata.getValue();
|
||||||
|
CompoundTag tag = item.getNbt();
|
||||||
|
|
||||||
|
if (tag == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
CompoundTag fireworks = tag.get("Fireworks");
|
||||||
|
|
||||||
|
CompoundTagBuilder fireworksBuilder = CompoundTagBuilder.builder();
|
||||||
|
if (fireworks.get("Flight") != null) {
|
||||||
|
fireworksBuilder.byteTag("Flight", MathUtils.convertByte(fireworks.get("Flight").getValue()));
|
||||||
|
}
|
||||||
|
|
||||||
|
List<com.nukkitx.nbt.tag.CompoundTag> explosions = new ArrayList<>();
|
||||||
|
if (fireworks.get("Explosions") != null) {
|
||||||
|
for (Tag effect : ((ListTag) fireworks.get("Explosions")).getValue()) {
|
||||||
|
CompoundTag effectData = (CompoundTag) effect;
|
||||||
|
CompoundTagBuilder effectBuilder = CompoundTagBuilder.builder();
|
||||||
|
|
||||||
|
if (effectData.get("Type") != null) {
|
||||||
|
effectBuilder.byteTag("FireworkType", MathUtils.convertByte(effectData.get("Type").getValue()));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (effectData.get("Colors") != null) {
|
||||||
|
int[] oldColors = (int[]) effectData.get("Colors").getValue();
|
||||||
|
byte[] colors = new byte[oldColors.length];
|
||||||
|
|
||||||
|
int i = 0;
|
||||||
|
for (int color : oldColors) {
|
||||||
|
colors[i++] = FireworkColor.fromJavaID(color).getBedrockID();
|
||||||
|
}
|
||||||
|
|
||||||
|
effectBuilder.byteArrayTag("FireworkColor", colors);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (effectData.get("FadeColors") != null) {
|
||||||
|
int[] oldColors = (int[]) effectData.get("FadeColors").getValue();
|
||||||
|
byte[] colors = new byte[oldColors.length];
|
||||||
|
|
||||||
|
int i = 0;
|
||||||
|
for (int color : oldColors) {
|
||||||
|
colors[i++] = FireworkColor.fromJavaID(color).getBedrockID();
|
||||||
|
}
|
||||||
|
|
||||||
|
effectBuilder.byteArrayTag("FireworkFade", colors);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (effectData.get("Trail") != null) {
|
||||||
|
effectBuilder.byteTag("FireworkTrail", MathUtils.convertByte(effectData.get("Trail").getValue()));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (effectData.get("Flicker") != null) {
|
||||||
|
effectBuilder.byteTag("FireworkFlicker", MathUtils.convertByte(effectData.get("Flicker").getValue()));
|
||||||
|
}
|
||||||
|
|
||||||
|
explosions.add(effectBuilder.buildRootTag());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fireworksBuilder.tag(new com.nukkitx.nbt.tag.ListTag<>("Explosions", com.nukkitx.nbt.tag.CompoundTag.class, explosions));
|
||||||
|
|
||||||
|
metadata.put(EntityData.DISPLAY_ITEM, CompoundTagBuilder.builder().tag(fireworksBuilder.build("Fireworks")).buildRootTag());
|
||||||
|
} else if (entityMetadata.getId() == 8 && !entityMetadata.getValue().equals(OptionalInt.empty()) && ((OptionalInt) entityMetadata.getValue()).getAsInt() == session.getPlayerEntity().getEntityId()) {
|
||||||
|
//Checks if the firework has an entity ID (used when a player is gliding) and checks to make sure the player that is gliding is the one getting sent the packet or else every player near the gliding player will boost too.
|
||||||
|
PlayerEntity entity = session.getPlayerEntity();
|
||||||
|
float yaw = entity.getRotation().getX();
|
||||||
|
float pitch = entity.getRotation().getY();
|
||||||
|
//Uses math from NukkitX
|
||||||
|
entity.setMotion(Vector3f.from(
|
||||||
|
-Math.sin(Math.toRadians(yaw)) * Math.cos(Math.toRadians(pitch)) * 2,
|
||||||
|
-Math.sin(Math.toRadians(pitch)) * 2,
|
||||||
|
Math.cos(Math.toRadians(yaw)) * Math.cos(Math.toRadians(pitch)) * 2));
|
||||||
|
//Need to update the EntityMotionPacket or else the player won't boost
|
||||||
|
SetEntityMotionPacket entityMotionPacket = new SetEntityMotionPacket();
|
||||||
|
entityMotionPacket.setRuntimeEntityId(entity.getGeyserId());
|
||||||
|
entityMotionPacket.setMotion(entity.getMotion());
|
||||||
|
|
||||||
|
session.sendUpstreamPacket(entityMotionPacket);
|
||||||
|
}
|
||||||
|
|
||||||
|
super.updateBedrockMetadata(entityMetadata, session);
|
||||||
|
}
|
||||||
|
}
|
|
@ -25,32 +25,44 @@
|
||||||
|
|
||||||
package org.geysermc.connector.entity;
|
package org.geysermc.connector.entity;
|
||||||
|
|
||||||
|
import com.github.steveice10.mc.protocol.data.game.entity.metadata.EntityMetadata;
|
||||||
|
import com.github.steveice10.mc.protocol.data.game.entity.object.ProjectileData;
|
||||||
import com.nukkitx.math.vector.Vector3f;
|
import com.nukkitx.math.vector.Vector3f;
|
||||||
import com.nukkitx.protocol.bedrock.packet.AddEntityPacket;
|
import com.nukkitx.protocol.bedrock.data.EntityData;
|
||||||
|
import org.geysermc.connector.GeyserConnector;
|
||||||
import org.geysermc.connector.entity.type.EntityType;
|
import org.geysermc.connector.entity.type.EntityType;
|
||||||
import org.geysermc.connector.network.session.GeyserSession;
|
import org.geysermc.connector.network.session.GeyserSession;
|
||||||
|
|
||||||
public class FishingHookEntity extends Entity {
|
public class FishingHookEntity extends Entity {
|
||||||
public FishingHookEntity(long entityId, long geyserId, EntityType entityType, Vector3f position, Vector3f motion, Vector3f rotation) {
|
public FishingHookEntity(long entityId, long geyserId, EntityType entityType, Vector3f position, Vector3f motion, Vector3f rotation, ProjectileData data) {
|
||||||
super(entityId, geyserId, entityType, position, motion, rotation);
|
super(entityId, geyserId, entityType, position, motion, rotation);
|
||||||
|
|
||||||
|
for (GeyserSession session : GeyserConnector.getInstance().getPlayers().values()) {
|
||||||
|
Entity entity = session.getEntityCache().getEntityByJavaId(data.getOwnerId());
|
||||||
|
if (entity == null && session.getPlayerEntity().getEntityId() == data.getOwnerId()) {
|
||||||
|
entity = session.getPlayerEntity();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (entity != null) {
|
||||||
|
this.metadata.put(EntityData.OWNER_EID, entity.getGeyserId());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void spawnEntity(GeyserSession session) {
|
public void updateBedrockMetadata(EntityMetadata entityMetadata, GeyserSession session) {
|
||||||
AddEntityPacket addEntityPacket = new AddEntityPacket();
|
if (entityMetadata.getId() == 7) {
|
||||||
// Different ID in Bedrock
|
Entity entity = session.getEntityCache().getEntityByJavaId((Integer) entityMetadata.getValue() - 1);
|
||||||
addEntityPacket.setIdentifier("minecraft:fishing_hook");
|
if (entity == null && session.getPlayerEntity().getEntityId() == (Integer) entityMetadata.getValue() - 1) {
|
||||||
addEntityPacket.setRuntimeEntityId(geyserId);
|
entity = session.getPlayerEntity();
|
||||||
addEntityPacket.setUniqueEntityId(geyserId);
|
}
|
||||||
addEntityPacket.setPosition(position);
|
|
||||||
addEntityPacket.setMotion(motion);
|
|
||||||
addEntityPacket.setRotation(getBedrockRotation());
|
|
||||||
addEntityPacket.setEntityType(entityType.getType());
|
|
||||||
addEntityPacket.getMetadata().putAll(metadata);
|
|
||||||
|
|
||||||
valid = true;
|
if (entity != null) {
|
||||||
session.getUpstream().sendPacket(addEntityPacket);
|
metadata.put(EntityData.TARGET_EID, entity.getGeyserId());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
session.getConnector().getLogger().debug("Spawned entity " + entityType + " at location " + position + " with id " + geyserId + " (java id " + entityId + ")");
|
super.updateBedrockMetadata(entityMetadata, session);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,86 @@
|
||||||
|
/*
|
||||||
|
* 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.connector.entity;
|
||||||
|
|
||||||
|
import com.github.steveice10.mc.protocol.data.game.entity.metadata.EntityMetadata;
|
||||||
|
import com.nukkitx.math.vector.Vector3f;
|
||||||
|
import com.nukkitx.protocol.bedrock.data.EntityData;
|
||||||
|
import org.geysermc.connector.entity.type.EntityType;
|
||||||
|
import org.geysermc.connector.network.session.GeyserSession;
|
||||||
|
import org.geysermc.connector.network.translators.world.block.BlockTranslator;
|
||||||
|
|
||||||
|
public class FurnaceMinecartEntity extends MinecartEntity {
|
||||||
|
|
||||||
|
private int customBlock = 0;
|
||||||
|
private int customBlockOffset = 0;
|
||||||
|
private boolean showCustomBlock = false;
|
||||||
|
private boolean hasFuel = false;
|
||||||
|
|
||||||
|
public FurnaceMinecartEntity(long entityId, long geyserId, EntityType entityType, Vector3f position, Vector3f motion, Vector3f rotation) {
|
||||||
|
super(entityId, geyserId, entityType, position, motion, rotation);
|
||||||
|
|
||||||
|
metadata.put(EntityData.DISPLAY_ITEM, BlockTranslator.getBedrockBlockId(BlockTranslator.JAVA_RUNTIME_FURNACE_ID));
|
||||||
|
metadata.put(EntityData.HAS_DISPLAY, (byte) 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void updateBedrockMetadata(EntityMetadata entityMetadata, GeyserSession session) {
|
||||||
|
|
||||||
|
// Custom block
|
||||||
|
if (entityMetadata.getId() == 10) {
|
||||||
|
customBlock = (int) entityMetadata.getValue();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Custom block offset
|
||||||
|
if (entityMetadata.getId() == 11) {
|
||||||
|
customBlockOffset = (int) entityMetadata.getValue();
|
||||||
|
}
|
||||||
|
|
||||||
|
// If the custom block should be enabled
|
||||||
|
if (entityMetadata.getId() == 12) {
|
||||||
|
if ((boolean) entityMetadata.getValue()) {
|
||||||
|
showCustomBlock = true;
|
||||||
|
metadata.put(EntityData.DISPLAY_ITEM, BlockTranslator.getBedrockBlockId(customBlock));
|
||||||
|
metadata.put(EntityData.DISPLAY_OFFSET, customBlockOffset);
|
||||||
|
} else {
|
||||||
|
showCustomBlock = false;
|
||||||
|
updateFurnaceMetadata();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (entityMetadata.getId() == 13 && !showCustomBlock) {
|
||||||
|
hasFuel = (boolean) entityMetadata.getValue();
|
||||||
|
updateFurnaceMetadata();
|
||||||
|
}
|
||||||
|
|
||||||
|
super.updateBedrockMetadata(entityMetadata, session);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void updateFurnaceMetadata() {
|
||||||
|
metadata.put(EntityData.DISPLAY_ITEM, BlockTranslator.getBedrockBlockId(hasFuel ? BlockTranslator.JAVA_RUNTIME_FURNACE_LIT_ID : BlockTranslator.JAVA_RUNTIME_FURNACE_ID));
|
||||||
|
metadata.put(EntityData.DISPLAY_OFFSET, 6);
|
||||||
|
}
|
||||||
|
}
|
|
@ -31,7 +31,7 @@ import com.nukkitx.math.vector.Vector3f;
|
||||||
import com.nukkitx.protocol.bedrock.packet.AddItemEntityPacket;
|
import com.nukkitx.protocol.bedrock.packet.AddItemEntityPacket;
|
||||||
import org.geysermc.connector.entity.type.EntityType;
|
import org.geysermc.connector.entity.type.EntityType;
|
||||||
import org.geysermc.connector.network.session.GeyserSession;
|
import org.geysermc.connector.network.session.GeyserSession;
|
||||||
import org.geysermc.connector.network.translators.Translators;
|
import org.geysermc.connector.network.translators.item.ItemTranslator;
|
||||||
|
|
||||||
public class ItemEntity extends Entity {
|
public class ItemEntity extends Entity {
|
||||||
|
|
||||||
|
@ -49,8 +49,8 @@ public class ItemEntity extends Entity {
|
||||||
itemPacket.setUniqueEntityId(geyserId);
|
itemPacket.setUniqueEntityId(geyserId);
|
||||||
itemPacket.setFromFishing(false);
|
itemPacket.setFromFishing(false);
|
||||||
itemPacket.getMetadata().putAll(metadata);
|
itemPacket.getMetadata().putAll(metadata);
|
||||||
itemPacket.setItemInHand(Translators.getItemTranslator().translateToBedrock(session, (ItemStack) entityMetadata.getValue()));
|
itemPacket.setItemInHand(ItemTranslator.translateToBedrock(session, (ItemStack) entityMetadata.getValue()));
|
||||||
session.getUpstream().sendPacket(itemPacket);
|
session.sendUpstreamPacket(itemPacket);
|
||||||
}
|
}
|
||||||
|
|
||||||
super.updateBedrockMetadata(entityMetadata, session);
|
super.updateBedrockMetadata(entityMetadata, session);
|
||||||
|
|
|
@ -0,0 +1,226 @@
|
||||||
|
/*
|
||||||
|
* 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.connector.entity;
|
||||||
|
|
||||||
|
import com.github.steveice10.mc.protocol.data.game.entity.metadata.EntityMetadata;
|
||||||
|
import com.github.steveice10.mc.protocol.data.game.entity.metadata.ItemStack;
|
||||||
|
import com.github.steveice10.mc.protocol.data.game.entity.object.HangingDirection;
|
||||||
|
import com.nukkitx.math.vector.Vector3f;
|
||||||
|
import com.nukkitx.math.vector.Vector3i;
|
||||||
|
import com.nukkitx.nbt.CompoundTagBuilder;
|
||||||
|
import com.nukkitx.nbt.tag.CompoundTag;
|
||||||
|
import com.nukkitx.protocol.bedrock.data.ItemData;
|
||||||
|
import com.nukkitx.protocol.bedrock.packet.BlockEntityDataPacket;
|
||||||
|
import com.nukkitx.protocol.bedrock.packet.StartGamePacket;
|
||||||
|
import com.nukkitx.protocol.bedrock.packet.UpdateBlockPacket;
|
||||||
|
import org.geysermc.connector.entity.type.EntityType;
|
||||||
|
import org.geysermc.connector.network.session.GeyserSession;
|
||||||
|
import org.geysermc.connector.network.translators.item.ItemEntry;
|
||||||
|
import org.geysermc.connector.network.translators.item.ItemRegistry;
|
||||||
|
import org.geysermc.connector.network.translators.item.ItemTranslator;
|
||||||
|
import org.geysermc.connector.network.translators.world.block.BlockTranslator;
|
||||||
|
|
||||||
|
import java.util.concurrent.TimeUnit;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Item frames are an entity in Java but a block entity in Bedrock.
|
||||||
|
*/
|
||||||
|
public class ItemFrameEntity extends Entity {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Used for getting the Bedrock block position.
|
||||||
|
* Blocks deal with integers whereas entities deal with floats.
|
||||||
|
*/
|
||||||
|
private final Vector3i bedrockPosition;
|
||||||
|
/**
|
||||||
|
* Specific block 'state' we are emulating in Bedrock.
|
||||||
|
*/
|
||||||
|
private final int bedrockRuntimeId;
|
||||||
|
/**
|
||||||
|
* Rotation of item in frame.
|
||||||
|
*/
|
||||||
|
private float rotation = 0.0f;
|
||||||
|
/**
|
||||||
|
* Cached item frame's Bedrock compound tag.
|
||||||
|
*/
|
||||||
|
private CompoundTag cachedTag;
|
||||||
|
|
||||||
|
public ItemFrameEntity(long entityId, long geyserId, EntityType entityType, Vector3f position, Vector3f motion, Vector3f rotation, HangingDirection direction) {
|
||||||
|
super(entityId, geyserId, entityType, position, motion, rotation);
|
||||||
|
CompoundTagBuilder builder = CompoundTag.builder();
|
||||||
|
builder.tag(CompoundTag.builder()
|
||||||
|
.stringTag("name", "minecraft:frame")
|
||||||
|
.intTag("version", BlockTranslator.getBlockStateVersion())
|
||||||
|
.tag(CompoundTag.builder()
|
||||||
|
.intTag("facing_direction", direction.ordinal())
|
||||||
|
.byteTag("item_frame_map_bit", (byte) 0)
|
||||||
|
.build("states"))
|
||||||
|
.build("block"));
|
||||||
|
builder.shortTag("id", (short) 199);
|
||||||
|
bedrockRuntimeId = BlockTranslator.getItemFrame(builder.buildRootTag());
|
||||||
|
bedrockPosition = Vector3i.from(position.getFloorX(), position.getFloorY(), position.getFloorZ());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void spawnEntity(GeyserSession session) {
|
||||||
|
session.getItemFrameCache().put(bedrockPosition, entityId);
|
||||||
|
// Delay is required, or else loading in frames on chunk load is sketchy at best
|
||||||
|
session.getConnector().getGeneralThreadPool().schedule(() -> {
|
||||||
|
updateBlock(session);
|
||||||
|
session.getConnector().getLogger().debug("Spawned item frame at location " + bedrockPosition + " with java id " + entityId);
|
||||||
|
}, 500, TimeUnit.MILLISECONDS);
|
||||||
|
valid = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void updateBedrockMetadata(EntityMetadata entityMetadata, GeyserSession session) {
|
||||||
|
if (entityMetadata.getId() == 7 && entityMetadata.getValue() != null) {
|
||||||
|
ItemData itemData = ItemTranslator.translateToBedrock(session, (ItemStack) entityMetadata.getValue());
|
||||||
|
ItemEntry itemEntry = ItemRegistry.getItem((ItemStack) entityMetadata.getValue());
|
||||||
|
CompoundTagBuilder builder = CompoundTag.builder();
|
||||||
|
|
||||||
|
String blockName = "";
|
||||||
|
for (StartGamePacket.ItemEntry startGamePacketItemEntry : ItemRegistry.ITEMS) {
|
||||||
|
if (startGamePacketItemEntry.getId() == (short) itemEntry.getBedrockId()) {
|
||||||
|
blockName = startGamePacketItemEntry.getIdentifier();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
builder.byteTag("Count", (byte) itemData.getCount());
|
||||||
|
if (itemData.getTag() != null) {
|
||||||
|
builder.tag(itemData.getTag().toBuilder().build("tag"));
|
||||||
|
}
|
||||||
|
builder.shortTag("Damage", itemData.getDamage());
|
||||||
|
builder.stringTag("Name", blockName);
|
||||||
|
CompoundTagBuilder tag = getDefaultTag().toBuilder();
|
||||||
|
tag.tag(builder.build("Item"));
|
||||||
|
tag.floatTag("ItemDropChance", 1.0f);
|
||||||
|
tag.floatTag("ItemRotation", rotation);
|
||||||
|
cachedTag = tag.buildRootTag();
|
||||||
|
updateBlock(session);
|
||||||
|
}
|
||||||
|
else if (entityMetadata.getId() == 7 && entityMetadata.getValue() == null && cachedTag != null) {
|
||||||
|
cachedTag = getDefaultTag();
|
||||||
|
updateBlock(session);
|
||||||
|
}
|
||||||
|
else if (entityMetadata.getId() == 8) {
|
||||||
|
rotation = ((int) entityMetadata.getValue()) * 45;
|
||||||
|
if (cachedTag == null) {
|
||||||
|
updateBlock(session);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
CompoundTagBuilder builder = cachedTag.toBuilder();
|
||||||
|
builder.floatTag("ItemRotation", rotation);
|
||||||
|
cachedTag = builder.buildRootTag();
|
||||||
|
updateBlock(session);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
updateBlock(session);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean despawnEntity(GeyserSession session) {
|
||||||
|
UpdateBlockPacket updateBlockPacket = new UpdateBlockPacket();
|
||||||
|
updateBlockPacket.setDataLayer(0);
|
||||||
|
updateBlockPacket.setBlockPosition(bedrockPosition);
|
||||||
|
updateBlockPacket.setRuntimeId(0);
|
||||||
|
updateBlockPacket.getFlags().add(UpdateBlockPacket.Flag.PRIORITY);
|
||||||
|
updateBlockPacket.getFlags().add(UpdateBlockPacket.Flag.NONE);
|
||||||
|
updateBlockPacket.getFlags().add(UpdateBlockPacket.Flag.NEIGHBORS);
|
||||||
|
session.sendUpstreamPacket(updateBlockPacket);
|
||||||
|
session.getItemFrameCache().remove(position, entityId);
|
||||||
|
valid = false;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
private CompoundTag getDefaultTag() {
|
||||||
|
CompoundTagBuilder builder = CompoundTag.builder();
|
||||||
|
builder.intTag("x", bedrockPosition.getX());
|
||||||
|
builder.intTag("y", bedrockPosition.getY());
|
||||||
|
builder.intTag("z", bedrockPosition.getZ());
|
||||||
|
builder.byteTag("isMovable", (byte) 1);
|
||||||
|
builder.stringTag("id", "ItemFrame");
|
||||||
|
return builder.buildRootTag();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Updates the item frame as a block
|
||||||
|
* @param session GeyserSession.
|
||||||
|
*/
|
||||||
|
public void updateBlock(GeyserSession session) {
|
||||||
|
UpdateBlockPacket updateBlockPacket = new UpdateBlockPacket();
|
||||||
|
updateBlockPacket.setDataLayer(0);
|
||||||
|
updateBlockPacket.setBlockPosition(bedrockPosition);
|
||||||
|
updateBlockPacket.setRuntimeId(bedrockRuntimeId);
|
||||||
|
updateBlockPacket.getFlags().add(UpdateBlockPacket.Flag.PRIORITY);
|
||||||
|
updateBlockPacket.getFlags().add(UpdateBlockPacket.Flag.NONE);
|
||||||
|
updateBlockPacket.getFlags().add(UpdateBlockPacket.Flag.NEIGHBORS);
|
||||||
|
session.sendUpstreamPacket(updateBlockPacket);
|
||||||
|
|
||||||
|
BlockEntityDataPacket blockEntityDataPacket = new BlockEntityDataPacket();
|
||||||
|
blockEntityDataPacket.setBlockPosition(bedrockPosition);
|
||||||
|
if (cachedTag != null) {
|
||||||
|
blockEntityDataPacket.setData(cachedTag);
|
||||||
|
} else {
|
||||||
|
blockEntityDataPacket.setData(getDefaultTag());
|
||||||
|
}
|
||||||
|
|
||||||
|
session.sendUpstreamPacket(blockEntityDataPacket);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Finds the Java entity ID of an item frame from its Bedrock position.
|
||||||
|
* @param position position of item frame in Bedrock.
|
||||||
|
* @param session GeyserSession.
|
||||||
|
* @return Java entity ID or -1 if not found.
|
||||||
|
*/
|
||||||
|
public static long getItemFrameEntityId(GeyserSession session, Vector3i position) {
|
||||||
|
return session.getItemFrameCache().getOrDefault(position, -1);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Determines if the position contains an item frame.
|
||||||
|
* Does largely the same thing as getItemFrameEntityId, but for speed purposes is implemented separately,
|
||||||
|
* since every block destroy packet has to check for an item frame.
|
||||||
|
* @param position position of block.
|
||||||
|
* @param session GeyserSession.
|
||||||
|
* @return true if position contains item frame, false if not.
|
||||||
|
*/
|
||||||
|
public static boolean positionContainsItemFrame(GeyserSession session, Vector3i position) {
|
||||||
|
return session.getItemFrameCache().containsKey(position);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Force-remove from the position-to-ID map so it doesn't cause conflicts.
|
||||||
|
* @param session GeyserSession.
|
||||||
|
* @param position position of the removed item frame.
|
||||||
|
*/
|
||||||
|
public static void removePosition(GeyserSession session, Vector3i position) {
|
||||||
|
session.getItemFrameCache().remove(position);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,39 @@
|
||||||
|
/*
|
||||||
|
* 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.connector.entity;
|
||||||
|
|
||||||
|
import com.nukkitx.math.vector.Vector3f;
|
||||||
|
import org.geysermc.connector.entity.type.EntityType;
|
||||||
|
|
||||||
|
public class LeashKnotEntity extends Entity {
|
||||||
|
|
||||||
|
public LeashKnotEntity(long entityId, long geyserId, EntityType entityType, Vector3f position, Vector3f motion, Vector3f rotation) {
|
||||||
|
// Position is incorrect by default
|
||||||
|
super(entityId, geyserId, entityType, position.add(0.5f, 0.25f, 0.5f), motion, rotation);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -96,8 +96,8 @@ public class LivingEntity extends Entity {
|
||||||
offHandPacket.setInventorySlot(0);
|
offHandPacket.setInventorySlot(0);
|
||||||
offHandPacket.setContainerId(ContainerId.OFFHAND);
|
offHandPacket.setContainerId(ContainerId.OFFHAND);
|
||||||
|
|
||||||
session.getUpstream().sendPacket(armorEquipmentPacket);
|
session.sendUpstreamPacket(armorEquipmentPacket);
|
||||||
session.getUpstream().sendPacket(handPacket);
|
session.sendUpstreamPacket(handPacket);
|
||||||
session.getUpstream().sendPacket(offHandPacket);
|
session.sendUpstreamPacket(offHandPacket);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -25,12 +25,59 @@
|
||||||
|
|
||||||
package org.geysermc.connector.entity;
|
package org.geysermc.connector.entity;
|
||||||
|
|
||||||
|
import com.github.steveice10.mc.protocol.data.game.entity.metadata.EntityMetadata;
|
||||||
import com.nukkitx.math.vector.Vector3f;
|
import com.nukkitx.math.vector.Vector3f;
|
||||||
|
import com.nukkitx.protocol.bedrock.data.EntityData;
|
||||||
import org.geysermc.connector.entity.type.EntityType;
|
import org.geysermc.connector.entity.type.EntityType;
|
||||||
|
import org.geysermc.connector.network.session.GeyserSession;
|
||||||
|
import org.geysermc.connector.network.translators.world.block.BlockTranslator;
|
||||||
|
|
||||||
public class MinecartEntity extends Entity {
|
public class MinecartEntity extends Entity {
|
||||||
|
|
||||||
public MinecartEntity(long entityId, long geyserId, EntityType entityType, Vector3f position, Vector3f motion, Vector3f rotation) {
|
public MinecartEntity(long entityId, long geyserId, EntityType entityType, Vector3f position, Vector3f motion, Vector3f rotation) {
|
||||||
super(entityId, geyserId, entityType, position, motion, rotation);
|
super(entityId, geyserId, entityType, position.add(0d, entityType.getOffset(), 0d), motion, rotation);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void updateBedrockMetadata(EntityMetadata entityMetadata, GeyserSession session) {
|
||||||
|
|
||||||
|
if (entityMetadata.getId() == 7) {
|
||||||
|
metadata.put(EntityData.HEALTH, entityMetadata.getValue());
|
||||||
|
}
|
||||||
|
|
||||||
|
// Direction in which the minecart is shaking
|
||||||
|
if (entityMetadata.getId() == 8) {
|
||||||
|
metadata.put(EntityData.HURT_DIRECTION, entityMetadata.getValue());
|
||||||
|
}
|
||||||
|
|
||||||
|
// Power in Java, time in Bedrock
|
||||||
|
if (entityMetadata.getId() == 9) {
|
||||||
|
metadata.put(EntityData.HURT_TIME, Math.min((int) (float) entityMetadata.getValue(), 15));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!(this instanceof FurnaceMinecartEntity)) { // Handled in FurnaceMinecartEntity.java
|
||||||
|
// Custom block
|
||||||
|
if (entityMetadata.getId() == 10) {
|
||||||
|
metadata.put(EntityData.DISPLAY_ITEM, BlockTranslator.getBedrockBlockId((int) entityMetadata.getValue()));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Custom block offset
|
||||||
|
if (entityMetadata.getId() == 11) {
|
||||||
|
metadata.put(EntityData.DISPLAY_OFFSET, entityMetadata.getValue());
|
||||||
|
}
|
||||||
|
|
||||||
|
// If the custom block should be enabled
|
||||||
|
if (entityMetadata.getId() == 12) {
|
||||||
|
// Needs a byte based off of Java's boolean
|
||||||
|
metadata.put(EntityData.HAS_DISPLAY, (byte) ((boolean) entityMetadata.getValue() ? 1 : 0));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
super.updateBedrockMetadata(entityMetadata, session);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void moveAbsolute(GeyserSession session, Vector3f position, Vector3f rotation, boolean isOnGround, boolean teleported) {
|
||||||
|
super.moveAbsolute(session, position.add(0d, this.entityType.getOffset(), 0d), rotation, isOnGround, teleported);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -55,7 +55,7 @@ public class PaintingEntity extends Entity {
|
||||||
addPaintingPacket.setName(paintingName.getBedrockName());
|
addPaintingPacket.setName(paintingName.getBedrockName());
|
||||||
addPaintingPacket.setPosition(fixOffset(true));
|
addPaintingPacket.setPosition(fixOffset(true));
|
||||||
addPaintingPacket.setDirection(direction);
|
addPaintingPacket.setDirection(direction);
|
||||||
session.getUpstream().sendPacket(addPaintingPacket);
|
session.sendUpstreamPacket(addPaintingPacket);
|
||||||
|
|
||||||
valid = true;
|
valid = true;
|
||||||
|
|
||||||
|
@ -67,7 +67,7 @@ public class PaintingEntity extends Entity {
|
||||||
Vector3f position = super.position;
|
Vector3f position = super.position;
|
||||||
position = position.add(0.5, 0.5, 0.5);
|
position = position.add(0.5, 0.5, 0.5);
|
||||||
double widthOffset = paintingName.getWidth() > 1 ? 0.5 : 0;
|
double widthOffset = paintingName.getWidth() > 1 ? 0.5 : 0;
|
||||||
double heightOffset = paintingName.getHeight() > 1 ? 0.5 : 0;
|
double heightOffset = paintingName.getHeight() > 1 && paintingName.getHeight() != 3 ? 0.5 : 0;
|
||||||
|
|
||||||
switch (direction) {
|
switch (direction) {
|
||||||
case 0: return position.add(widthOffset, heightOffset, OFFSET);
|
case 0: return position.add(widthOffset, heightOffset, OFFSET);
|
||||||
|
|
|
@ -26,15 +26,13 @@
|
||||||
package org.geysermc.connector.entity;
|
package org.geysermc.connector.entity;
|
||||||
|
|
||||||
import com.github.steveice10.mc.auth.data.GameProfile;
|
import com.github.steveice10.mc.auth.data.GameProfile;
|
||||||
|
import com.github.steveice10.mc.protocol.data.game.entity.Effect;
|
||||||
import com.github.steveice10.mc.protocol.data.game.entity.metadata.EntityMetadata;
|
import com.github.steveice10.mc.protocol.data.game.entity.metadata.EntityMetadata;
|
||||||
import com.github.steveice10.mc.protocol.data.message.TextMessage;
|
import com.github.steveice10.mc.protocol.data.message.TextMessage;
|
||||||
|
import com.github.steveice10.opennbt.tag.builtin.CompoundTag;
|
||||||
import com.nukkitx.math.vector.Vector3f;
|
import com.nukkitx.math.vector.Vector3f;
|
||||||
import com.nukkitx.protocol.bedrock.data.CommandPermission;
|
import com.nukkitx.protocol.bedrock.data.*;
|
||||||
import com.nukkitx.protocol.bedrock.data.EntityData;
|
import com.nukkitx.protocol.bedrock.packet.*;
|
||||||
import com.nukkitx.protocol.bedrock.data.PlayerPermission;
|
|
||||||
import com.nukkitx.protocol.bedrock.packet.AddPlayerPacket;
|
|
||||||
import com.nukkitx.protocol.bedrock.packet.MovePlayerPacket;
|
|
||||||
import com.nukkitx.protocol.bedrock.packet.PlayerListPacket;
|
|
||||||
|
|
||||||
import lombok.Getter;
|
import lombok.Getter;
|
||||||
import lombok.Setter;
|
import lombok.Setter;
|
||||||
|
@ -47,7 +45,10 @@ import org.geysermc.connector.utils.MessageUtils;
|
||||||
import org.geysermc.connector.network.session.cache.EntityEffectCache;
|
import org.geysermc.connector.network.session.cache.EntityEffectCache;
|
||||||
import org.geysermc.connector.utils.SkinUtils;
|
import org.geysermc.connector.utils.SkinUtils;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
|
import java.util.concurrent.TimeUnit;
|
||||||
|
|
||||||
@Getter @Setter
|
@Getter @Setter
|
||||||
public class PlayerEntity extends LivingEntity {
|
public class PlayerEntity extends LivingEntity {
|
||||||
|
@ -56,8 +57,12 @@ public class PlayerEntity extends LivingEntity {
|
||||||
private String username;
|
private String username;
|
||||||
private long lastSkinUpdate = -1;
|
private long lastSkinUpdate = -1;
|
||||||
private boolean playerList = true;
|
private boolean playerList = true;
|
||||||
|
private boolean onGround;
|
||||||
private final EntityEffectCache effectCache;
|
private final EntityEffectCache effectCache;
|
||||||
|
|
||||||
|
private Entity leftParrot;
|
||||||
|
private Entity rightParrot;
|
||||||
|
|
||||||
public PlayerEntity(GameProfile gameProfile, long entityId, long geyserId, Vector3f position, Vector3f motion, Vector3f rotation) {
|
public PlayerEntity(GameProfile gameProfile, long entityId, long geyserId, Vector3f position, Vector3f motion, Vector3f rotation) {
|
||||||
super(entityId, geyserId, EntityType.PLAYER, position, motion, rotation);
|
super(entityId, geyserId, EntityType.PLAYER, position, motion, rotation);
|
||||||
|
|
||||||
|
@ -83,7 +88,7 @@ public class PlayerEntity extends LivingEntity {
|
||||||
addPlayerPacket.setUsername(username);
|
addPlayerPacket.setUsername(username);
|
||||||
addPlayerPacket.setRuntimeEntityId(geyserId);
|
addPlayerPacket.setRuntimeEntityId(geyserId);
|
||||||
addPlayerPacket.setUniqueEntityId(geyserId);
|
addPlayerPacket.setUniqueEntityId(geyserId);
|
||||||
addPlayerPacket.setPosition(position);
|
addPlayerPacket.setPosition(position.clone().sub(0, EntityType.PLAYER.getOffset(), 0));
|
||||||
addPlayerPacket.setRotation(getBedrockRotation());
|
addPlayerPacket.setRotation(getBedrockRotation());
|
||||||
addPlayerPacket.setMotion(motion);
|
addPlayerPacket.setMotion(motion);
|
||||||
addPlayerPacket.setHand(hand);
|
addPlayerPacket.setHand(hand);
|
||||||
|
@ -93,20 +98,27 @@ public class PlayerEntity extends LivingEntity {
|
||||||
addPlayerPacket.setPlatformChatId("");
|
addPlayerPacket.setPlatformChatId("");
|
||||||
addPlayerPacket.getMetadata().putAll(metadata);
|
addPlayerPacket.getMetadata().putAll(metadata);
|
||||||
|
|
||||||
|
long linkedEntityId = session.getEntityCache().getCachedPlayerEntityLink(entityId);
|
||||||
|
if (linkedEntityId != -1) {
|
||||||
|
addPlayerPacket.getEntityLinks().add(new EntityLink(session.getEntityCache().getEntityByJavaId(linkedEntityId).getGeyserId(), geyserId, EntityLink.Type.RIDER, false));
|
||||||
|
}
|
||||||
|
|
||||||
valid = true;
|
valid = true;
|
||||||
session.getUpstream().sendPacket(addPlayerPacket);
|
session.sendUpstreamPacket(addPlayerPacket);
|
||||||
|
|
||||||
updateEquipment(session);
|
updateEquipment(session);
|
||||||
updateBedrockAttributes(session);
|
updateBedrockAttributes(session);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void sendPlayer(GeyserSession session) {
|
public void sendPlayer(GeyserSession session) {
|
||||||
|
if(session.getEntityCache().getPlayerEntity(uuid) == null)
|
||||||
|
return;
|
||||||
if (getLastSkinUpdate() == -1) {
|
if (getLastSkinUpdate() == -1) {
|
||||||
if (playerList) {
|
if (playerList) {
|
||||||
PlayerListPacket playerList = new PlayerListPacket();
|
PlayerListPacket playerList = new PlayerListPacket();
|
||||||
playerList.setAction(PlayerListPacket.Action.ADD);
|
playerList.setAction(PlayerListPacket.Action.ADD);
|
||||||
playerList.getEntries().add(SkinUtils.buildDefaultEntry(profile, geyserId));
|
playerList.getEntries().add(SkinUtils.buildDefaultEntry(profile, geyserId));
|
||||||
session.getUpstream().sendPacket(playerList);
|
session.sendUpstreamPacket(playerList);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -122,24 +134,36 @@ public class PlayerEntity extends LivingEntity {
|
||||||
PlayerListPacket playerList = new PlayerListPacket();
|
PlayerListPacket playerList = new PlayerListPacket();
|
||||||
playerList.setAction(PlayerListPacket.Action.REMOVE);
|
playerList.setAction(PlayerListPacket.Action.REMOVE);
|
||||||
playerList.getEntries().add(new PlayerListPacket.Entry(uuid));
|
playerList.getEntries().add(new PlayerListPacket.Entry(uuid));
|
||||||
session.getUpstream().sendPacket(playerList);
|
session.sendUpstreamPacket(playerList);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void moveAbsolute(GeyserSession session, Vector3f position, Vector3f rotation, boolean isOnGround) {
|
public void moveAbsolute(GeyserSession session, Vector3f position, Vector3f rotation, boolean isOnGround, boolean teleported) {
|
||||||
setPosition(position);
|
setPosition(position);
|
||||||
setRotation(rotation);
|
setRotation(rotation);
|
||||||
|
|
||||||
|
this.onGround = isOnGround;
|
||||||
|
|
||||||
MovePlayerPacket movePlayerPacket = new MovePlayerPacket();
|
MovePlayerPacket movePlayerPacket = new MovePlayerPacket();
|
||||||
movePlayerPacket.setRuntimeEntityId(geyserId);
|
movePlayerPacket.setRuntimeEntityId(geyserId);
|
||||||
movePlayerPacket.setPosition(this.position);
|
movePlayerPacket.setPosition(this.position);
|
||||||
movePlayerPacket.setRotation(getBedrockRotation());
|
movePlayerPacket.setRotation(getBedrockRotation());
|
||||||
movePlayerPacket.setOnGround(isOnGround);
|
movePlayerPacket.setOnGround(isOnGround);
|
||||||
movePlayerPacket.setMode(MovePlayerPacket.Mode.NORMAL);
|
movePlayerPacket.setMode(teleported ? MovePlayerPacket.Mode.TELEPORT : MovePlayerPacket.Mode.NORMAL);
|
||||||
|
|
||||||
session.getUpstream().sendPacket(movePlayerPacket);
|
if (teleported) {
|
||||||
|
movePlayerPacket.setTeleportationCause(MovePlayerPacket.TeleportationCause.UNKNOWN);
|
||||||
|
}
|
||||||
|
|
||||||
|
session.sendUpstreamPacket(movePlayerPacket);
|
||||||
|
if (leftParrot != null) {
|
||||||
|
leftParrot.moveAbsolute(session, position, rotation, true, teleported);
|
||||||
|
}
|
||||||
|
if (rightParrot != null) {
|
||||||
|
rightParrot.moveAbsolute(session, position, rotation, true, teleported);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -147,13 +171,21 @@ public class PlayerEntity extends LivingEntity {
|
||||||
setRotation(rotation);
|
setRotation(rotation);
|
||||||
this.position = Vector3f.from(position.getX() + relX, position.getY() + relY, position.getZ() + relZ);
|
this.position = Vector3f.from(position.getX() + relX, position.getY() + relY, position.getZ() + relZ);
|
||||||
|
|
||||||
|
this.onGround = isOnGround;
|
||||||
|
|
||||||
MovePlayerPacket movePlayerPacket = new MovePlayerPacket();
|
MovePlayerPacket movePlayerPacket = new MovePlayerPacket();
|
||||||
movePlayerPacket.setRuntimeEntityId(geyserId);
|
movePlayerPacket.setRuntimeEntityId(geyserId);
|
||||||
movePlayerPacket.setPosition(position);
|
movePlayerPacket.setPosition(position);
|
||||||
movePlayerPacket.setRotation(getBedrockRotation());
|
movePlayerPacket.setRotation(getBedrockRotation());
|
||||||
movePlayerPacket.setOnGround(isOnGround);
|
movePlayerPacket.setOnGround(isOnGround);
|
||||||
movePlayerPacket.setMode(MovePlayerPacket.Mode.NORMAL);
|
movePlayerPacket.setMode(MovePlayerPacket.Mode.NORMAL);
|
||||||
session.getUpstream().sendPacket(movePlayerPacket);
|
session.sendUpstreamPacket(movePlayerPacket);
|
||||||
|
if (leftParrot != null) {
|
||||||
|
leftParrot.moveRelative(session, relX, relY, relZ, rotation, true);
|
||||||
|
}
|
||||||
|
if (rightParrot != null) {
|
||||||
|
rightParrot.moveRelative(session, relX, relY, relZ, rotation, true);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -182,5 +214,54 @@ public class PlayerEntity extends LivingEntity {
|
||||||
metadata.put(EntityData.NAMETAG, team.getPrefix() + MessageUtils.toChatColor(team.getColor()) + username + team.getSuffix());
|
metadata.put(EntityData.NAMETAG, team.getPrefix() + MessageUtils.toChatColor(team.getColor()) + username + team.getSuffix());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Extra hearts - is not metadata but an attribute on Bedrock
|
||||||
|
if (entityMetadata.getId() == 14) {
|
||||||
|
UpdateAttributesPacket attributesPacket = new UpdateAttributesPacket();
|
||||||
|
attributesPacket.setRuntimeEntityId(geyserId);
|
||||||
|
List<Attribute> attributes = new ArrayList<>();
|
||||||
|
// Setting to a higher maximum since plugins/datapacks can probably extend the Bedrock soft limit
|
||||||
|
attributes.add(new Attribute("minecraft:absorption", 0.0f, 1024f, (float) entityMetadata.getValue(), 0.0f));
|
||||||
|
attributesPacket.setAttributes(attributes);
|
||||||
|
session.sendUpstreamPacket(attributesPacket);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Parrot occupying shoulder
|
||||||
|
if (entityMetadata.getId() == 18 || entityMetadata.getId() == 19) {
|
||||||
|
CompoundTag tag = (CompoundTag) entityMetadata.getValue();
|
||||||
|
if (tag != null && !tag.isEmpty()) {
|
||||||
|
// The parrot is a separate entity in Bedrock, but part of the player entity in Java
|
||||||
|
Entity parrot = new Entity(0, session.getEntityCache().getNextEntityId().incrementAndGet(),
|
||||||
|
EntityType.PARROT, position, motion, rotation);
|
||||||
|
parrot.spawnEntity(session);
|
||||||
|
parrot.getMetadata().put(EntityData.VARIANT, tag.get("Variant").getValue());
|
||||||
|
// Different position whether the parrot is left or right
|
||||||
|
float offset = (entityMetadata.getId() == 18) ? 0.4f : -0.4f;
|
||||||
|
parrot.getMetadata().put(EntityData.RIDER_SEAT_POSITION, Vector3f.from(offset, -0.22, -0.1));
|
||||||
|
parrot.getMetadata().put(EntityData.RIDER_ROTATION_LOCKED, 1);
|
||||||
|
parrot.updateBedrockMetadata(session);
|
||||||
|
SetEntityLinkPacket linkPacket = new SetEntityLinkPacket();
|
||||||
|
EntityLink.Type type = (entityMetadata.getId() == 18) ? EntityLink.Type.RIDER : EntityLink.Type.PASSENGER;
|
||||||
|
linkPacket.setEntityLink(new EntityLink(geyserId, parrot.getGeyserId(), type, false));
|
||||||
|
// Delay, or else spawned-in players won't get the link
|
||||||
|
// TODO: Find a better solution. This problem also exists with item frames
|
||||||
|
session.getConnector().getGeneralThreadPool().schedule(() -> session.sendUpstreamPacket(linkPacket), 500, TimeUnit.MILLISECONDS);
|
||||||
|
if (entityMetadata.getId() == 18) {
|
||||||
|
leftParrot = parrot;
|
||||||
|
} else {
|
||||||
|
rightParrot = parrot;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
Entity parrot = (entityMetadata.getId() == 18 ? leftParrot : rightParrot);
|
||||||
|
if (parrot != null) {
|
||||||
|
parrot.despawnEntity(session);
|
||||||
|
if (entityMetadata.getId() == 18) {
|
||||||
|
leftParrot = null;
|
||||||
|
} else {
|
||||||
|
rightParrot = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,65 @@
|
||||||
|
/*
|
||||||
|
* 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.connector.entity;
|
||||||
|
|
||||||
|
import com.github.steveice10.mc.protocol.data.game.entity.metadata.EntityMetadata;
|
||||||
|
import com.nukkitx.math.vector.Vector3f;
|
||||||
|
import com.nukkitx.protocol.bedrock.data.EntityData;
|
||||||
|
import com.nukkitx.protocol.bedrock.data.EntityFlag;
|
||||||
|
import org.geysermc.connector.entity.type.EntityType;
|
||||||
|
import org.geysermc.connector.network.session.GeyserSession;
|
||||||
|
|
||||||
|
import java.util.concurrent.ScheduledFuture;
|
||||||
|
import java.util.concurrent.TimeUnit;
|
||||||
|
|
||||||
|
public class TNTEntity extends Entity {
|
||||||
|
|
||||||
|
private int currentTick;
|
||||||
|
|
||||||
|
public TNTEntity(long entityId, long geyserId, EntityType entityType, Vector3f position, Vector3f motion, Vector3f rotation) {
|
||||||
|
super(entityId, geyserId, entityType, position, motion, rotation);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void updateBedrockMetadata(EntityMetadata entityMetadata, GeyserSession session) {
|
||||||
|
if (entityMetadata.getId() == 7) {
|
||||||
|
currentTick = (int) entityMetadata.getValue();
|
||||||
|
metadata.getFlags().setFlag(EntityFlag.IGNITED, true);
|
||||||
|
metadata.put(EntityData.FUSE_LENGTH, currentTick);
|
||||||
|
ScheduledFuture<?> future = session.getConnector().getGeneralThreadPool().scheduleAtFixedRate(() -> {
|
||||||
|
if (currentTick % 5 == 0) {
|
||||||
|
metadata.put(EntityData.FUSE_LENGTH, currentTick);
|
||||||
|
}
|
||||||
|
currentTick--;
|
||||||
|
super.updateBedrockMetadata(entityMetadata, session);
|
||||||
|
}, 50, 50, TimeUnit.MILLISECONDS); // 5 ticks
|
||||||
|
session.getConnector().getGeneralThreadPool().schedule(() -> future.cancel(true), (int) entityMetadata.getValue() / 20, TimeUnit.SECONDS);
|
||||||
|
}
|
||||||
|
|
||||||
|
super.updateBedrockMetadata(entityMetadata, session);
|
||||||
|
}
|
||||||
|
}
|
|
@ -23,23 +23,14 @@
|
||||||
* @link https://github.com/GeyserMC/Geyser
|
* @link https://github.com/GeyserMC/Geyser
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package org.geysermc.connector.network.translators;
|
package org.geysermc.connector.entity;
|
||||||
|
|
||||||
import com.github.steveice10.opennbt.tag.builtin.CompoundTag;
|
import com.nukkitx.math.vector.Vector3f;
|
||||||
import org.geysermc.connector.network.translators.item.ItemEntry;
|
import org.geysermc.connector.entity.type.EntityType;
|
||||||
|
|
||||||
public class NbtItemStackTranslator {
|
public class TippedArrowEntity extends AbstractArrowEntity {
|
||||||
|
|
||||||
public void translateToBedrock(CompoundTag itemTag, ItemEntry itemEntry) {
|
|
||||||
|
|
||||||
|
public TippedArrowEntity(long entityId, long geyserId, EntityType entityType, Vector3f position, Vector3f motion, Vector3f rotation) {
|
||||||
|
super(entityId, geyserId, entityType, position, motion, rotation);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void translateToJava(CompoundTag itemTag, ItemEntry itemEntry) {
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean acceptItem(ItemEntry itemEntry) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
|
@ -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.connector.entity;
|
||||||
|
|
||||||
|
import com.github.steveice10.mc.protocol.data.game.entity.metadata.EntityMetadata;
|
||||||
|
import com.nukkitx.math.vector.Vector3f;
|
||||||
|
import com.nukkitx.protocol.bedrock.data.EntityFlag;
|
||||||
|
import org.geysermc.connector.entity.type.EntityType;
|
||||||
|
import org.geysermc.connector.network.session.GeyserSession;
|
||||||
|
|
||||||
|
public class TridentEntity extends AbstractArrowEntity {
|
||||||
|
|
||||||
|
public TridentEntity(long entityId, long geyserId, EntityType entityType, Vector3f position, Vector3f motion, Vector3f rotation) {
|
||||||
|
super(entityId, geyserId, entityType, position, motion, rotation);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void updateBedrockMetadata(EntityMetadata entityMetadata, GeyserSession session) {
|
||||||
|
if (entityMetadata.getId() == 11) {
|
||||||
|
metadata.getFlags().setFlag(EntityFlag.ENCHANTED, (boolean) entityMetadata.getValue());
|
||||||
|
}
|
||||||
|
|
||||||
|
super.updateBedrockMetadata(entityMetadata, session);
|
||||||
|
}
|
||||||
|
}
|
|
@ -38,6 +38,7 @@ public enum AttributeType {
|
||||||
MOVEMENT_SPEED("generic.movementSpeed", "minecraft:movement", 0f, 1024f, 0.1f),
|
MOVEMENT_SPEED("generic.movementSpeed", "minecraft:movement", 0f, 1024f, 0.1f),
|
||||||
FLYING_SPEED("generic.flyingSpeed", "minecraft:movement", 0.0f, 1024.0f, 0.4000000059604645f),
|
FLYING_SPEED("generic.flyingSpeed", "minecraft:movement", 0.0f, 1024.0f, 0.4000000059604645f),
|
||||||
ATTACK_DAMAGE("generic.attackDamage", "minecraft:attack_damage", 0f, 2048f, 1f),
|
ATTACK_DAMAGE("generic.attackDamage", "minecraft:attack_damage", 0f, 2048f, 1f),
|
||||||
|
HORSE_JUMP_STRENGTH("horse.jumpStrength", "minecraft:horse.jump_strength", 0.0f, 2.0f, 0.7f),
|
||||||
|
|
||||||
// Java Attributes
|
// Java Attributes
|
||||||
ARMOR("generic.armor", null, 0f, 30f, 0f),
|
ARMOR("generic.armor", null, 0f, 30f, 0f),
|
||||||
|
|
|
@ -25,28 +25,18 @@
|
||||||
|
|
||||||
package org.geysermc.connector.entity.living;
|
package org.geysermc.connector.entity.living;
|
||||||
|
|
||||||
import com.github.steveice10.mc.protocol.data.game.entity.metadata.EntityMetadata;
|
|
||||||
import com.nukkitx.math.vector.Vector3f;
|
import com.nukkitx.math.vector.Vector3f;
|
||||||
import com.nukkitx.protocol.bedrock.data.EntityData;
|
|
||||||
import com.nukkitx.protocol.bedrock.data.EntityFlag;
|
import com.nukkitx.protocol.bedrock.data.EntityFlag;
|
||||||
import org.geysermc.connector.entity.type.EntityType;
|
import org.geysermc.connector.entity.type.EntityType;
|
||||||
import org.geysermc.connector.network.session.GeyserSession;
|
|
||||||
|
|
||||||
public class AbstractFishEntity extends WaterEntity {
|
public class AbstractFishEntity extends WaterEntity {
|
||||||
|
|
||||||
public AbstractFishEntity(long entityId, long geyserId, EntityType entityType, Vector3f position, Vector3f motion, Vector3f rotation) {
|
public AbstractFishEntity(long entityId, long geyserId, EntityType entityType, Vector3f position, Vector3f motion, Vector3f rotation) {
|
||||||
super(entityId, geyserId, entityType, position, motion, rotation);
|
super(entityId, geyserId, entityType, position, motion, rotation);
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void updateBedrockMetadata(EntityMetadata entityMetadata, GeyserSession session) {
|
|
||||||
metadata.getFlags().setFlag(EntityFlag.CAN_SWIM, true);
|
metadata.getFlags().setFlag(EntityFlag.CAN_SWIM, true);
|
||||||
metadata.getFlags().setFlag(EntityFlag.BREATHING, true);
|
metadata.getFlags().setFlag(EntityFlag.BREATHING, true);
|
||||||
metadata.getFlags().setFlag(EntityFlag.CAN_CLIMB, false);
|
metadata.getFlags().setFlag(EntityFlag.CAN_CLIMB, false);
|
||||||
metadata.getFlags().setFlag(EntityFlag.HAS_GRAVITY, false);
|
metadata.getFlags().setFlag(EntityFlag.HAS_GRAVITY, false);
|
||||||
|
|
||||||
metadata.put(EntityData.AIR, (short) 400);
|
|
||||||
|
|
||||||
super.updateBedrockMetadata(entityMetadata, session);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -44,6 +44,9 @@ public class AgeableEntity extends CreatureEntity {
|
||||||
boolean isBaby = (boolean) entityMetadata.getValue();
|
boolean isBaby = (boolean) entityMetadata.getValue();
|
||||||
metadata.put(EntityData.SCALE, isBaby ? .55f : 1f);
|
metadata.put(EntityData.SCALE, isBaby ? .55f : 1f);
|
||||||
metadata.getFlags().setFlag(EntityFlag.BABY, isBaby);
|
metadata.getFlags().setFlag(EntityFlag.BABY, isBaby);
|
||||||
|
|
||||||
|
metadata.put(EntityData.BOUNDING_BOX_HEIGHT, entityType.getHeight() * (isBaby ? 0.55f : 1f));
|
||||||
|
metadata.put(EntityData.BOUNDING_BOX_WIDTH, entityType.getWidth() * (isBaby ? 0.55f : 1f));
|
||||||
}
|
}
|
||||||
|
|
||||||
super.updateBedrockMetadata(entityMetadata, session);
|
super.updateBedrockMetadata(entityMetadata, session);
|
||||||
|
|
|
@ -43,8 +43,26 @@ public class ArmorStandEntity extends LivingEntity {
|
||||||
public void updateBedrockMetadata(EntityMetadata entityMetadata, GeyserSession session) {
|
public void updateBedrockMetadata(EntityMetadata entityMetadata, GeyserSession session) {
|
||||||
if (entityMetadata.getType() == MetadataType.BYTE) {
|
if (entityMetadata.getType() == MetadataType.BYTE) {
|
||||||
byte xd = (byte) entityMetadata.getValue();
|
byte xd = (byte) entityMetadata.getValue();
|
||||||
if ((xd & 0x01) == 0x01 && (metadata.get(EntityData.SCALE) != null && !metadata.get(EntityData.SCALE).equals(0.0f))) {
|
|
||||||
metadata.put(EntityData.SCALE, .55f);
|
// isSmall
|
||||||
|
if ((xd & 0x01) == 0x01) {
|
||||||
|
if (metadata.getFloat(EntityData.SCALE) != 0.55f && metadata.getFloat(EntityData.SCALE) != 0.0f) {
|
||||||
|
metadata.put(EntityData.SCALE, 0.55f);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (metadata.get(EntityData.BOUNDING_BOX_WIDTH) != null && metadata.get(EntityData.BOUNDING_BOX_WIDTH).equals(0.5f)) {
|
||||||
|
metadata.put(EntityData.BOUNDING_BOX_WIDTH, 0.25f);
|
||||||
|
metadata.put(EntityData.BOUNDING_BOX_HEIGHT, 0.9875f);
|
||||||
|
}
|
||||||
|
} else if (metadata.get(EntityData.BOUNDING_BOX_WIDTH) != null && metadata.get(EntityData.BOUNDING_BOX_WIDTH).equals(0.25f)) {
|
||||||
|
metadata.put(EntityData.BOUNDING_BOX_WIDTH, entityType.getWidth());
|
||||||
|
metadata.put(EntityData.BOUNDING_BOX_HEIGHT, entityType.getHeight());
|
||||||
|
}
|
||||||
|
|
||||||
|
// setMarker
|
||||||
|
if ((xd & 0x10) == 0x10 && (metadata.get(EntityData.BOUNDING_BOX_WIDTH) != null && !metadata.get(EntityData.BOUNDING_BOX_WIDTH).equals(0.0f))) {
|
||||||
|
metadata.put(EntityData.BOUNDING_BOX_WIDTH, 0.0f);
|
||||||
|
metadata.put(EntityData.BOUNDING_BOX_HEIGHT, 0.0f);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
super.updateBedrockMetadata(entityMetadata, session);
|
super.updateBedrockMetadata(entityMetadata, session);
|
||||||
|
|
|
@ -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.connector.entity.living;
|
||||||
|
|
||||||
|
import com.github.steveice10.mc.protocol.data.game.entity.metadata.EntityMetadata;
|
||||||
|
import com.nukkitx.math.vector.Vector3f;
|
||||||
|
import com.nukkitx.protocol.bedrock.data.EntityData;
|
||||||
|
import org.geysermc.connector.entity.type.EntityType;
|
||||||
|
import org.geysermc.connector.network.session.GeyserSession;
|
||||||
|
|
||||||
|
public class SlimeEntity extends InsentientEntity {
|
||||||
|
|
||||||
|
public SlimeEntity(long entityId, long geyserId, EntityType entityType, Vector3f position, Vector3f motion, Vector3f rotation) {
|
||||||
|
super(entityId, geyserId, entityType, position, motion, rotation);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void updateBedrockMetadata(EntityMetadata entityMetadata, GeyserSession session) {
|
||||||
|
if (entityMetadata.getId() == 15) {
|
||||||
|
this.metadata.put(EntityData.SCALE, 0.10f + (int) entityMetadata.getValue());
|
||||||
|
}
|
||||||
|
super.updateBedrockMetadata(entityMetadata, session);
|
||||||
|
}
|
||||||
|
}
|
|
@ -23,14 +23,14 @@
|
||||||
* @link https://github.com/GeyserMC/Geyser
|
* @link https://github.com/GeyserMC/Geyser
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package org.geysermc.connector.entity;
|
package org.geysermc.connector.entity.living;
|
||||||
|
|
||||||
import com.nukkitx.math.vector.Vector3f;
|
import com.nukkitx.math.vector.Vector3f;
|
||||||
import org.geysermc.connector.entity.type.EntityType;
|
import org.geysermc.connector.entity.type.EntityType;
|
||||||
|
|
||||||
public class ArrowEntity extends Entity {
|
public class SquidEntity extends WaterEntity {
|
||||||
|
|
||||||
public ArrowEntity(long entityId, long geyserId, EntityType entityType, Vector3f position, Vector3f motion, Vector3f rotation) {
|
public SquidEntity(long entityId, long geyserId, EntityType entityType, Vector3f position, Vector3f motion, Vector3f rotation) {
|
||||||
super(entityId, geyserId, entityType, position, motion, rotation);
|
super(entityId, geyserId, entityType, position, motion, rotation);
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -26,11 +26,14 @@
|
||||||
package org.geysermc.connector.entity.living;
|
package org.geysermc.connector.entity.living;
|
||||||
|
|
||||||
import com.nukkitx.math.vector.Vector3f;
|
import com.nukkitx.math.vector.Vector3f;
|
||||||
|
import com.nukkitx.protocol.bedrock.data.EntityData;
|
||||||
import org.geysermc.connector.entity.type.EntityType;
|
import org.geysermc.connector.entity.type.EntityType;
|
||||||
|
|
||||||
public class WaterEntity extends CreatureEntity {
|
public class WaterEntity extends CreatureEntity {
|
||||||
|
|
||||||
public WaterEntity(long entityId, long geyserId, EntityType entityType, Vector3f position, Vector3f motion, Vector3f rotation) {
|
public WaterEntity(long entityId, long geyserId, EntityType entityType, Vector3f position, Vector3f motion, Vector3f rotation) {
|
||||||
super(entityId, geyserId, entityType, position, motion, rotation);
|
super(entityId, geyserId, entityType, position, motion, rotation);
|
||||||
|
|
||||||
|
metadata.put(EntityData.AIR, (short) 400);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -28,7 +28,6 @@ package org.geysermc.connector.entity.living.animal;
|
||||||
import com.github.steveice10.mc.protocol.data.game.entity.metadata.EntityMetadata;
|
import com.github.steveice10.mc.protocol.data.game.entity.metadata.EntityMetadata;
|
||||||
import com.nukkitx.math.vector.Vector3f;
|
import com.nukkitx.math.vector.Vector3f;
|
||||||
import com.nukkitx.protocol.bedrock.data.EntityData;
|
import com.nukkitx.protocol.bedrock.data.EntityData;
|
||||||
import com.nukkitx.protocol.bedrock.packet.AddEntityPacket;
|
|
||||||
import lombok.AllArgsConstructor;
|
import lombok.AllArgsConstructor;
|
||||||
import lombok.Getter;
|
import lombok.Getter;
|
||||||
import org.geysermc.connector.entity.living.AbstractFishEntity;
|
import org.geysermc.connector.entity.living.AbstractFishEntity;
|
||||||
|
@ -54,24 +53,6 @@ public class TropicalFishEntity extends AbstractFishEntity {
|
||||||
super.updateBedrockMetadata(entityMetadata, session);
|
super.updateBedrockMetadata(entityMetadata, session);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public void spawnEntity(GeyserSession session) {
|
|
||||||
AddEntityPacket addEntityPacket = new AddEntityPacket();
|
|
||||||
addEntityPacket.setIdentifier("minecraft:tropicalfish");
|
|
||||||
addEntityPacket.setRuntimeEntityId(geyserId);
|
|
||||||
addEntityPacket.setUniqueEntityId(geyserId);
|
|
||||||
addEntityPacket.setPosition(position);
|
|
||||||
addEntityPacket.setMotion(motion);
|
|
||||||
addEntityPacket.setRotation(getBedrockRotation());
|
|
||||||
addEntityPacket.setEntityType(entityType.getType());
|
|
||||||
addEntityPacket.getMetadata().putAll(metadata);
|
|
||||||
|
|
||||||
valid = true;
|
|
||||||
session.getUpstream().sendPacket(addEntityPacket);
|
|
||||||
|
|
||||||
session.getConnector().getLogger().debug("Spawned entity " + entityType + " at location " + position + " with id " + geyserId + " (java id " + entityId + ")");
|
|
||||||
}
|
|
||||||
|
|
||||||
@Getter
|
@Getter
|
||||||
@AllArgsConstructor
|
@AllArgsConstructor
|
||||||
private static class TropicalFishVariant {
|
private static class TropicalFishVariant {
|
||||||
|
|
|
@ -27,25 +27,69 @@ package org.geysermc.connector.entity.living.animal.horse;
|
||||||
|
|
||||||
import com.github.steveice10.mc.protocol.data.game.entity.metadata.EntityMetadata;
|
import com.github.steveice10.mc.protocol.data.game.entity.metadata.EntityMetadata;
|
||||||
import com.nukkitx.math.vector.Vector3f;
|
import com.nukkitx.math.vector.Vector3f;
|
||||||
|
import com.nukkitx.protocol.bedrock.data.Attribute;
|
||||||
import com.nukkitx.protocol.bedrock.data.EntityFlag;
|
import com.nukkitx.protocol.bedrock.data.EntityFlag;
|
||||||
|
import com.nukkitx.protocol.bedrock.packet.UpdateAttributesPacket;
|
||||||
|
import org.geysermc.connector.entity.attribute.AttributeType;
|
||||||
import org.geysermc.connector.entity.living.animal.AnimalEntity;
|
import org.geysermc.connector.entity.living.animal.AnimalEntity;
|
||||||
import org.geysermc.connector.entity.type.EntityType;
|
import org.geysermc.connector.entity.type.EntityType;
|
||||||
import org.geysermc.connector.network.session.GeyserSession;
|
import org.geysermc.connector.network.session.GeyserSession;
|
||||||
|
import org.geysermc.connector.utils.AttributeUtils;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
public class AbstractHorseEntity extends AnimalEntity {
|
public class AbstractHorseEntity extends AnimalEntity {
|
||||||
|
|
||||||
|
// For updating the horse visual easier
|
||||||
|
private float health = 20f;
|
||||||
|
|
||||||
public AbstractHorseEntity(long entityId, long geyserId, EntityType entityType, Vector3f position, Vector3f motion, Vector3f rotation) {
|
public AbstractHorseEntity(long entityId, long geyserId, EntityType entityType, Vector3f position, Vector3f motion, Vector3f rotation) {
|
||||||
super(entityId, geyserId, entityType, position, motion, rotation);
|
super(entityId, geyserId, entityType, position, motion, rotation);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void updateBedrockMetadata(EntityMetadata entityMetadata, GeyserSession session) {
|
public void updateBedrockMetadata(EntityMetadata entityMetadata, GeyserSession session) {
|
||||||
|
|
||||||
|
if (entityMetadata.getId() == 8) {
|
||||||
|
health = (float) entityMetadata.getValue();
|
||||||
|
updateBedrockAttributes(session);
|
||||||
|
}
|
||||||
|
|
||||||
if (entityMetadata.getId() == 16) {
|
if (entityMetadata.getId() == 16) {
|
||||||
byte xd = (byte) entityMetadata.getValue();
|
byte xd = (byte) entityMetadata.getValue();
|
||||||
metadata.getFlags().setFlag(EntityFlag.TAMED, (xd & 0x02) == 0x02);
|
metadata.getFlags().setFlag(EntityFlag.TAMED, (xd & 0x02) == 0x02);
|
||||||
metadata.getFlags().setFlag(EntityFlag.SADDLED, (xd & 0x04) == 0x04);
|
metadata.getFlags().setFlag(EntityFlag.SADDLED, (xd & 0x04) == 0x04);
|
||||||
metadata.getFlags().setFlag(EntityFlag.EATING, (xd & 0x10) == 0x10);
|
metadata.getFlags().setFlag(EntityFlag.EATING, (xd & 0x10) == 0x10);
|
||||||
|
metadata.getFlags().setFlag(EntityFlag.STANDING, (xd & 0x20) == 0x20);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Needed to control horses
|
||||||
|
metadata.getFlags().setFlag(EntityFlag.CAN_POWER_JUMP, true);
|
||||||
|
metadata.getFlags().setFlag(EntityFlag.WASD_CONTROLLED, true);
|
||||||
|
|
||||||
super.updateBedrockMetadata(entityMetadata, session);
|
super.updateBedrockMetadata(entityMetadata, session);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void updateBedrockAttributes(GeyserSession session) {
|
||||||
|
if (!valid) return;
|
||||||
|
|
||||||
|
float maxHealth = attributes.containsKey(AttributeType.MAX_HEALTH) ? attributes.get(AttributeType.MAX_HEALTH).getValue() : 20f;
|
||||||
|
|
||||||
|
List<com.nukkitx.protocol.bedrock.data.Attribute> attributesLocal = new ArrayList<>();
|
||||||
|
for (Map.Entry<AttributeType, org.geysermc.connector.entity.attribute.Attribute> entry : this.attributes.entrySet()) {
|
||||||
|
if (!entry.getValue().getType().isBedrockAttribute())
|
||||||
|
continue;
|
||||||
|
|
||||||
|
attributesLocal.add(AttributeUtils.getBedrockAttribute(entry.getValue()));
|
||||||
|
}
|
||||||
|
attributesLocal.add(new Attribute("minecraft:health", 0.0f, maxHealth, health, maxHealth));
|
||||||
|
|
||||||
|
UpdateAttributesPacket updateAttributesPacket = new UpdateAttributesPacket();
|
||||||
|
updateAttributesPacket.setRuntimeEntityId(geyserId);
|
||||||
|
updateAttributesPacket.setAttributes(attributesLocal);
|
||||||
|
session.sendUpstreamPacket(updateAttributesPacket);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -28,6 +28,7 @@ package org.geysermc.connector.entity.living.animal.horse;
|
||||||
import com.github.steveice10.mc.protocol.data.game.entity.metadata.EntityMetadata;
|
import com.github.steveice10.mc.protocol.data.game.entity.metadata.EntityMetadata;
|
||||||
import com.nukkitx.math.vector.Vector3f;
|
import com.nukkitx.math.vector.Vector3f;
|
||||||
import com.nukkitx.protocol.bedrock.data.EntityData;
|
import com.nukkitx.protocol.bedrock.data.EntityData;
|
||||||
|
import com.nukkitx.protocol.bedrock.data.EntityFlag;
|
||||||
import org.geysermc.connector.entity.type.EntityType;
|
import org.geysermc.connector.entity.type.EntityType;
|
||||||
import org.geysermc.connector.network.session.GeyserSession;
|
import org.geysermc.connector.network.session.GeyserSession;
|
||||||
|
|
||||||
|
@ -41,8 +42,9 @@ public class HorseEntity extends AbstractHorseEntity {
|
||||||
public void updateBedrockMetadata(EntityMetadata entityMetadata, GeyserSession session) {
|
public void updateBedrockMetadata(EntityMetadata entityMetadata, GeyserSession session) {
|
||||||
if (entityMetadata.getId() == 18) {
|
if (entityMetadata.getId() == 18) {
|
||||||
metadata.put(EntityData.VARIANT, (int) entityMetadata.getValue());
|
metadata.put(EntityData.VARIANT, (int) entityMetadata.getValue());
|
||||||
|
metadata.put(EntityData.MARK_VARIANT, (((int) entityMetadata.getValue()) >> 8) % 5);
|
||||||
}
|
}
|
||||||
|
|
||||||
super.updateBedrockMetadata(entityMetadata, session);
|
super.updateBedrockMetadata(entityMetadata, session);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
|
@ -32,7 +32,7 @@ import com.nukkitx.protocol.bedrock.data.ItemData;
|
||||||
import com.nukkitx.protocol.bedrock.packet.MobArmorEquipmentPacket;
|
import com.nukkitx.protocol.bedrock.packet.MobArmorEquipmentPacket;
|
||||||
import org.geysermc.connector.entity.type.EntityType;
|
import org.geysermc.connector.entity.type.EntityType;
|
||||||
import org.geysermc.connector.network.session.GeyserSession;
|
import org.geysermc.connector.network.session.GeyserSession;
|
||||||
import org.geysermc.connector.network.translators.block.BlockTranslator;
|
import org.geysermc.connector.network.translators.world.block.BlockTranslator;
|
||||||
|
|
||||||
public class LlamaEntity extends ChestedHorseEntity {
|
public class LlamaEntity extends ChestedHorseEntity {
|
||||||
|
|
||||||
|
@ -65,7 +65,7 @@ public class LlamaEntity extends ChestedHorseEntity {
|
||||||
equipmentPacket.setHelmet(ItemData.AIR);
|
equipmentPacket.setHelmet(ItemData.AIR);
|
||||||
equipmentPacket.setLeggings(ItemData.AIR);
|
equipmentPacket.setLeggings(ItemData.AIR);
|
||||||
|
|
||||||
session.getUpstream().sendPacket(equipmentPacket);
|
session.sendUpstreamPacket(equipmentPacket);
|
||||||
}
|
}
|
||||||
// Color of the llama
|
// Color of the llama
|
||||||
if (entityMetadata.getId() == 21) {
|
if (entityMetadata.getId() == 21) {
|
||||||
|
|
|
@ -27,7 +27,6 @@ package org.geysermc.connector.entity.living.animal.horse;
|
||||||
|
|
||||||
import com.nukkitx.math.vector.Vector3f;
|
import com.nukkitx.math.vector.Vector3f;
|
||||||
import com.nukkitx.protocol.bedrock.data.EntityData;
|
import com.nukkitx.protocol.bedrock.data.EntityData;
|
||||||
import com.nukkitx.protocol.bedrock.packet.AddEntityPacket;
|
|
||||||
import org.geysermc.connector.entity.type.EntityType;
|
import org.geysermc.connector.entity.type.EntityType;
|
||||||
import org.geysermc.connector.network.session.GeyserSession;
|
import org.geysermc.connector.network.session.GeyserSession;
|
||||||
|
|
||||||
|
@ -39,23 +38,7 @@ public class TraderLlamaEntity extends LlamaEntity {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void spawnEntity(GeyserSession session) {
|
public void spawnEntity(GeyserSession session) {
|
||||||
// The trader llama is a separate entity from the llama in Java but a normal llama with extra metadata in Bedrock.
|
this.metadata.put(EntityData.MARK_VARIANT, 1);
|
||||||
AddEntityPacket addEntityPacket = new AddEntityPacket();
|
super.spawnEntity(session);
|
||||||
addEntityPacket.setIdentifier("minecraft:llama");
|
|
||||||
addEntityPacket.setRuntimeEntityId(geyserId);
|
|
||||||
addEntityPacket.setUniqueEntityId(geyserId);
|
|
||||||
addEntityPacket.setPosition(position);
|
|
||||||
addEntityPacket.setMotion(motion);
|
|
||||||
addEntityPacket.setRotation(getBedrockRotation());
|
|
||||||
addEntityPacket.setEntityType(entityType.getType());
|
|
||||||
addEntityPacket.getMetadata().putAll(metadata);
|
|
||||||
// Here's the difference
|
|
||||||
addEntityPacket.getMetadata().put(EntityData.MARK_VARIANT, 1);
|
|
||||||
|
|
||||||
valid = true;
|
|
||||||
session.getUpstream().sendPacket(addEntityPacket);
|
|
||||||
|
|
||||||
session.getConnector().getLogger().debug("Spawned entity " + entityType + " at location " + position + " with id " + geyserId + " (java id " + entityId + ")");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -29,7 +29,6 @@ import com.github.steveice10.mc.protocol.data.game.entity.metadata.EntityMetadat
|
||||||
import com.github.steveice10.mc.protocol.data.game.entity.metadata.VillagerData;
|
import com.github.steveice10.mc.protocol.data.game.entity.metadata.VillagerData;
|
||||||
import com.nukkitx.math.vector.Vector3f;
|
import com.nukkitx.math.vector.Vector3f;
|
||||||
import com.nukkitx.protocol.bedrock.data.EntityData;
|
import com.nukkitx.protocol.bedrock.data.EntityData;
|
||||||
import com.nukkitx.protocol.bedrock.packet.AddEntityPacket;
|
|
||||||
import it.unimi.dsi.fastutil.ints.Int2IntMap;
|
import it.unimi.dsi.fastutil.ints.Int2IntMap;
|
||||||
import it.unimi.dsi.fastutil.ints.Int2IntOpenHashMap;
|
import it.unimi.dsi.fastutil.ints.Int2IntOpenHashMap;
|
||||||
import org.geysermc.connector.entity.type.EntityType;
|
import org.geysermc.connector.entity.type.EntityType;
|
||||||
|
@ -85,24 +84,4 @@ public class VillagerEntity extends AbstractMerchantEntity {
|
||||||
}
|
}
|
||||||
super.updateBedrockMetadata(entityMetadata, session);
|
super.updateBedrockMetadata(entityMetadata, session);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public void spawnEntity(GeyserSession session) {
|
|
||||||
AddEntityPacket addEntityPacket = new AddEntityPacket();
|
|
||||||
// "v2" or else it's the legacy villager
|
|
||||||
addEntityPacket.setIdentifier("minecraft:villager_v2");
|
|
||||||
addEntityPacket.setRuntimeEntityId(geyserId);
|
|
||||||
addEntityPacket.setUniqueEntityId(geyserId);
|
|
||||||
addEntityPacket.setPosition(position);
|
|
||||||
addEntityPacket.setMotion(motion);
|
|
||||||
addEntityPacket.setRotation(getBedrockRotation());
|
|
||||||
addEntityPacket.setEntityType(entityType.getType());
|
|
||||||
addEntityPacket.getMetadata().putAll(metadata);
|
|
||||||
|
|
||||||
valid = true;
|
|
||||||
session.getUpstream().sendPacket(addEntityPacket);
|
|
||||||
|
|
||||||
session.getConnector().getLogger().debug("Spawned entity " + entityType + " at location " + position + " with id " + geyserId + " (java id " + entityId + ")");
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -39,8 +39,8 @@ public class CreeperEntity extends MonsterEntity {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void updateBedrockMetadata(EntityMetadata entityMetadata, GeyserSession session) {
|
public void updateBedrockMetadata(EntityMetadata entityMetadata, GeyserSession session) {
|
||||||
if (entityMetadata.getId() == 15 && (int) entityMetadata.getValue() > 0) {
|
if (entityMetadata.getId() == 15) {
|
||||||
metadata.getFlags().setFlag(EntityFlag.IGNITED, true);
|
metadata.getFlags().setFlag(EntityFlag.IGNITED, (int) entityMetadata.getValue() == 1);
|
||||||
}
|
}
|
||||||
if (entityMetadata.getId() == 16) {
|
if (entityMetadata.getId() == 16) {
|
||||||
metadata.getFlags().setFlag(EntityFlag.POWERED, (boolean) entityMetadata.getValue());
|
metadata.getFlags().setFlag(EntityFlag.POWERED, (boolean) entityMetadata.getValue());
|
||||||
|
|
|
@ -0,0 +1,41 @@
|
||||||
|
/*
|
||||||
|
* 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.connector.entity.living.monster;
|
||||||
|
|
||||||
|
import com.nukkitx.math.vector.Vector3f;
|
||||||
|
import com.nukkitx.protocol.bedrock.data.EntityFlag;
|
||||||
|
import org.geysermc.connector.entity.type.EntityType;
|
||||||
|
|
||||||
|
public class ElderGuardianEntity extends GuardianEntity {
|
||||||
|
|
||||||
|
public ElderGuardianEntity(long entityId, long geyserId, EntityType entityType, Vector3f position, Vector3f motion, Vector3f rotation) {
|
||||||
|
super(entityId, geyserId, entityType, position, motion, rotation);
|
||||||
|
// Otherwise it just looks like a normal guardian but bigger
|
||||||
|
metadata.getFlags().setFlag(EntityFlag.ELDER, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -53,7 +53,7 @@ public class EnderDragonEntity extends InsentientEntity {
|
||||||
entityEventPacket.setType(EntityEventType.DRAGON_FLAMING);
|
entityEventPacket.setType(EntityEventType.DRAGON_FLAMING);
|
||||||
entityEventPacket.setRuntimeEntityId(geyserId);
|
entityEventPacket.setRuntimeEntityId(geyserId);
|
||||||
entityEventPacket.setData(0);
|
entityEventPacket.setData(0);
|
||||||
session.getUpstream().sendPacket(entityEventPacket);
|
session.sendUpstreamPacket(entityEventPacket);
|
||||||
case 6:
|
case 6:
|
||||||
case 7:
|
case 7:
|
||||||
metadata.getFlags().setFlag(EntityFlag.SITTING, true);
|
metadata.getFlags().setFlag(EntityFlag.SITTING, true);
|
||||||
|
@ -79,7 +79,7 @@ public class EnderDragonEntity extends InsentientEntity {
|
||||||
addEntityPacket.getAttributes().add(new Attribute("minecraft:health", 0.0f, 200f, 200f, 200f));
|
addEntityPacket.getAttributes().add(new Attribute("minecraft:health", 0.0f, 200f, 200f, 200f));
|
||||||
|
|
||||||
valid = true;
|
valid = true;
|
||||||
session.getUpstream().sendPacket(addEntityPacket);
|
session.sendUpstreamPacket(addEntityPacket);
|
||||||
|
|
||||||
session.getConnector().getLogger().debug("Spawned entity " + entityType + " at location " + position + " with id " + geyserId + " (java id " + entityId + ")");
|
session.getConnector().getLogger().debug("Spawned entity " + entityType + " at location " + position + " with id " + geyserId + " (java id " + entityId + ")");
|
||||||
}
|
}
|
||||||
|
|
|
@ -32,7 +32,7 @@ import com.nukkitx.protocol.bedrock.data.EntityData;
|
||||||
import com.nukkitx.protocol.bedrock.data.EntityFlag;
|
import com.nukkitx.protocol.bedrock.data.EntityFlag;
|
||||||
import org.geysermc.connector.entity.type.EntityType;
|
import org.geysermc.connector.entity.type.EntityType;
|
||||||
import org.geysermc.connector.network.session.GeyserSession;
|
import org.geysermc.connector.network.session.GeyserSession;
|
||||||
import org.geysermc.connector.network.translators.block.BlockTranslator;
|
import org.geysermc.connector.network.translators.world.block.BlockTranslator;
|
||||||
|
|
||||||
public class EndermanEntity extends MonsterEntity {
|
public class EndermanEntity extends MonsterEntity {
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,39 @@
|
||||||
|
/*
|
||||||
|
* 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.connector.entity.living.monster;
|
||||||
|
|
||||||
|
import com.nukkitx.math.vector.Vector3f;
|
||||||
|
import com.nukkitx.protocol.bedrock.data.EntityData;
|
||||||
|
import org.geysermc.connector.entity.type.EntityType;
|
||||||
|
|
||||||
|
public class GiantEntity extends MonsterEntity {
|
||||||
|
|
||||||
|
public GiantEntity(long entityId, long geyserId, EntityType entityType, Vector3f position, Vector3f motion, Vector3f rotation) {
|
||||||
|
super(entityId, geyserId, entityType, position, motion, rotation);
|
||||||
|
|
||||||
|
metadata.put(EntityData.SCALE, 6f);
|
||||||
|
}
|
||||||
|
}
|
|
@ -42,8 +42,14 @@ public class GuardianEntity extends MonsterEntity {
|
||||||
public void updateBedrockMetadata(EntityMetadata entityMetadata, GeyserSession session) {
|
public void updateBedrockMetadata(EntityMetadata entityMetadata, GeyserSession session) {
|
||||||
if (entityMetadata.getId() == 16) {
|
if (entityMetadata.getId() == 16) {
|
||||||
Entity entity = session.getEntityCache().getEntityByJavaId((int) entityMetadata.getValue());
|
Entity entity = session.getEntityCache().getEntityByJavaId((int) entityMetadata.getValue());
|
||||||
|
if (entity == null && session.getPlayerEntity().getEntityId() == (Integer) entityMetadata.getValue()) {
|
||||||
|
entity = session.getPlayerEntity();
|
||||||
|
}
|
||||||
|
|
||||||
if (entity != null) {
|
if (entity != null) {
|
||||||
metadata.put(EntityData.TARGET_EID, entity.getGeyserId());
|
metadata.put(EntityData.TARGET_EID, entity.getGeyserId());
|
||||||
|
} else {
|
||||||
|
metadata.put(EntityData.TARGET_EID, (long) 0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,77 @@
|
||||||
|
/*
|
||||||
|
* 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.connector.entity.living.monster;
|
||||||
|
|
||||||
|
import com.github.steveice10.mc.protocol.data.game.entity.metadata.EntityMetadata;
|
||||||
|
import com.nukkitx.math.vector.Vector3f;
|
||||||
|
import com.nukkitx.protocol.bedrock.data.EntityData;
|
||||||
|
import org.geysermc.connector.entity.Entity;
|
||||||
|
import org.geysermc.connector.entity.type.EntityType;
|
||||||
|
import org.geysermc.connector.network.session.GeyserSession;
|
||||||
|
|
||||||
|
public class WitherEntity extends MonsterEntity {
|
||||||
|
|
||||||
|
public WitherEntity(long entityId, long geyserId, EntityType entityType, Vector3f position, Vector3f motion, Vector3f rotation) {
|
||||||
|
super(entityId, geyserId, entityType, position, motion, rotation);
|
||||||
|
|
||||||
|
metadata.put(EntityData.WITHER_AERIAL_ATTACK, (short) 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void updateBedrockMetadata(EntityMetadata entityMetadata, GeyserSession session) {
|
||||||
|
long targetID = 0;
|
||||||
|
|
||||||
|
if (entityMetadata.getId() >= 15 && entityMetadata.getId() <= 17) {
|
||||||
|
Entity entity = session.getEntityCache().getEntityByJavaId((int) entityMetadata.getValue());
|
||||||
|
if (entity == null && session.getPlayerEntity().getEntityId() == (Integer) entityMetadata.getValue()) {
|
||||||
|
entity = session.getPlayerEntity();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (entity != null) {
|
||||||
|
targetID = entity.getGeyserId();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (entityMetadata.getId() == 15) {
|
||||||
|
metadata.put(EntityData.WITHER_TARGET_1, targetID);
|
||||||
|
} else if (entityMetadata.getId() == 16) {
|
||||||
|
metadata.put(EntityData.WITHER_TARGET_2, targetID);
|
||||||
|
} else if (entityMetadata.getId() == 17) {
|
||||||
|
metadata.put(EntityData.WITHER_TARGET_3, targetID);
|
||||||
|
} else if (entityMetadata.getId() == 18) {
|
||||||
|
metadata.put(EntityData.WITHER_INVULNERABLE_TICKS, (int) entityMetadata.getValue());
|
||||||
|
|
||||||
|
// Show the shield for the first few seconds of spawning (like Java)
|
||||||
|
if ((int) entityMetadata.getValue() >= 165) {
|
||||||
|
metadata.put(EntityData.WITHER_AERIAL_ATTACK, (short) 0);
|
||||||
|
} else {
|
||||||
|
metadata.put(EntityData.WITHER_AERIAL_ATTACK, (short) 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
super.updateBedrockMetadata(entityMetadata, session);
|
||||||
|
}
|
||||||
|
}
|
|
@ -45,9 +45,9 @@ public enum EntityType {
|
||||||
PIG(PigEntity.class, 12, 0.9f),
|
PIG(PigEntity.class, 12, 0.9f),
|
||||||
SHEEP(SheepEntity.class, 13, 1.3f, 0.9f),
|
SHEEP(SheepEntity.class, 13, 1.3f, 0.9f),
|
||||||
WOLF(WolfEntity.class, 14, 0.85f, 0.6f),
|
WOLF(WolfEntity.class, 14, 0.85f, 0.6f),
|
||||||
VILLAGER(VillagerEntity.class, 15, 1.8f, 0.6f, 0.6f, 1.62f),
|
VILLAGER(VillagerEntity.class, 15, 1.8f, 0.6f, 0.6f, 1.62f, "minecraft:villager_v2"),
|
||||||
MOOSHROOM(AnimalEntity.class, 16, 1.4f, 0.9f),
|
MOOSHROOM(AnimalEntity.class, 16, 1.4f, 0.9f),
|
||||||
SQUID(WaterEntity.class, 17, 0.8f),
|
SQUID(SquidEntity.class, 17, 0.8f),
|
||||||
RABBIT(RabbitEntity.class, 18, 0.5f, 0.4f),
|
RABBIT(RabbitEntity.class, 18, 0.5f, 0.4f),
|
||||||
BAT(AmbientEntity.class, 19, 0.9f, 0.5f),
|
BAT(AmbientEntity.class, 19, 0.9f, 0.5f),
|
||||||
IRON_GOLEM(GolemEntity.class, 20, 2.7f, 1.4f),
|
IRON_GOLEM(GolemEntity.class, 20, 2.7f, 1.4f),
|
||||||
|
@ -60,20 +60,21 @@ public enum EntityType {
|
||||||
ZOMBIE_HORSE(AbstractHorseEntity.class, 27, 1.6f, 1.3965f),
|
ZOMBIE_HORSE(AbstractHorseEntity.class, 27, 1.6f, 1.3965f),
|
||||||
POLAR_BEAR(PolarBearEntity.class, 28, 1.4f, 1.3f),
|
POLAR_BEAR(PolarBearEntity.class, 28, 1.4f, 1.3f),
|
||||||
LLAMA(LlamaEntity.class, 29, 1.87f, 0.9f),
|
LLAMA(LlamaEntity.class, 29, 1.87f, 0.9f),
|
||||||
TRADER_LLAMA(TraderLlamaEntity.class, 29, 1.187f, 0.9f),
|
TRADER_LLAMA(TraderLlamaEntity.class, 29, 1.187f, 0.9f, 0f, 0f, "minecraft:llama"),
|
||||||
PARROT(ParrotEntity.class, 30, 0.9f, 0.5f),
|
PARROT(ParrotEntity.class, 30, 0.9f, 0.5f),
|
||||||
DOLPHIN(WaterEntity.class, 31, 0.6f, 0.9f),
|
DOLPHIN(WaterEntity.class, 31, 0.6f, 0.9f),
|
||||||
ZOMBIE(ZombieEntity.class, 32, 1.8f, 0.6f, 0.6f, 1.62f),
|
ZOMBIE(ZombieEntity.class, 32, 1.8f, 0.6f, 0.6f, 1.62f),
|
||||||
|
GIANT(GiantEntity.class, 32, 1.8f, 0.6f, 0.6f, 1.62f, "minecraft:zombie"),
|
||||||
CREEPER(CreeperEntity.class, 33, 1.7f, 0.6f, 0.6f, 1.62f),
|
CREEPER(CreeperEntity.class, 33, 1.7f, 0.6f, 0.6f, 1.62f),
|
||||||
SKELETON(AbstractSkeletonEntity.class, 34, 1.8f, 0.6f, 0.6f, 1.62f),
|
SKELETON(AbstractSkeletonEntity.class, 34, 1.8f, 0.6f, 0.6f, 1.62f),
|
||||||
SPIDER(SpiderEntity.class, 35, 0.9f, 1.4f, 1.4f, 1f),
|
SPIDER(SpiderEntity.class, 35, 0.9f, 1.4f, 1.4f, 1f),
|
||||||
ZOMBIE_PIGMAN(MonsterEntity.class, 36, 1.8f, 0.6f, 0.6f, 1.62f),
|
ZOMBIE_PIGMAN(MonsterEntity.class, 36, 1.8f, 0.6f, 0.6f, 1.62f),
|
||||||
SLIME(InsentientEntity.class, 37, 0.51f),
|
SLIME(SlimeEntity.class, 37, 0.51f),
|
||||||
ENDERMAN(EndermanEntity.class, 38, 2.9f, 0.6f),
|
ENDERMAN(EndermanEntity.class, 38, 2.9f, 0.6f),
|
||||||
SILVERFISH(MonsterEntity.class, 39, 0.3f, 0.4f),
|
SILVERFISH(MonsterEntity.class, 39, 0.3f, 0.4f),
|
||||||
CAVE_SPIDER(MonsterEntity.class, 40, 0.5f, 0.7f),
|
CAVE_SPIDER(MonsterEntity.class, 40, 0.5f, 0.7f),
|
||||||
GHAST(FlyingEntity.class, 41, 4.0f),
|
GHAST(FlyingEntity.class, 41, 4.0f),
|
||||||
MAGMA_CUBE(InsentientEntity.class, 42, 0.51f),
|
MAGMA_CUBE(SlimeEntity.class, 42, 0.51f),
|
||||||
BLAZE(BlazeEntity.class, 43, 1.8f, 0.6f),
|
BLAZE(BlazeEntity.class, 43, 1.8f, 0.6f),
|
||||||
ZOMBIE_VILLAGER(ZombieEntity.class, 44, 1.8f, 0.6f, 0.6f, 1.62f),
|
ZOMBIE_VILLAGER(ZombieEntity.class, 44, 1.8f, 0.6f, 0.6f, 1.62f),
|
||||||
WITCH(RaidParticipantEntity.class, 45, 1.8f, 0.6f, 0.6f, 1.62f),
|
WITCH(RaidParticipantEntity.class, 45, 1.8f, 0.6f, 0.6f, 1.62f),
|
||||||
|
@ -81,9 +82,9 @@ public enum EntityType {
|
||||||
HUSK(ZombieEntity.class, 47, 1.8f, 0.6f, 0.6f, 1.62f),
|
HUSK(ZombieEntity.class, 47, 1.8f, 0.6f, 0.6f, 1.62f),
|
||||||
WITHER_SKELETON(AbstractSkeletonEntity.class, 48, 2.4f, 0.7f),
|
WITHER_SKELETON(AbstractSkeletonEntity.class, 48, 2.4f, 0.7f),
|
||||||
GUARDIAN(GuardianEntity.class, 49, 0.85f),
|
GUARDIAN(GuardianEntity.class, 49, 0.85f),
|
||||||
ELDER_GUARDIAN(GuardianEntity.class, 50, 1.9975f),
|
ELDER_GUARDIAN(ElderGuardianEntity.class, 50, 1.9975f),
|
||||||
NPC(PlayerEntity.class, 51, 1.8f, 0.6f, 0.6f, 1.62f),
|
NPC(PlayerEntity.class, 51, 1.8f, 0.6f, 0.6f, 1.62f),
|
||||||
WITHER(MonsterEntity.class, 52, 3.5f, 0.9f),
|
WITHER(WitherEntity.class, 52, 3.5f, 0.9f),
|
||||||
ENDER_DRAGON(EnderDragonEntity.class, 53, 4f, 13f),
|
ENDER_DRAGON(EnderDragonEntity.class, 53, 4f, 13f),
|
||||||
SHULKER(ShulkerEntity.class, 54, 1f, 1f),
|
SHULKER(ShulkerEntity.class, 54, 1f, 1f),
|
||||||
ENDERMITE(MonsterEntity.class, 55, 0.3f, 0.4f),
|
ENDERMITE(MonsterEntity.class, 55, 0.3f, 0.4f),
|
||||||
|
@ -94,60 +95,73 @@ public enum EntityType {
|
||||||
PHANTOM(FlyingEntity.class, 58, 0.5f, 0.9f, 0.9f, 0.6f),
|
PHANTOM(FlyingEntity.class, 58, 0.5f, 0.9f, 0.9f, 0.6f),
|
||||||
RAVAGER(RaidParticipantEntity.class, 59, 1.9f, 1.2f),
|
RAVAGER(RaidParticipantEntity.class, 59, 1.9f, 1.2f),
|
||||||
|
|
||||||
ARMOR_STAND(ArmorStandEntity.class, 61, 0f),
|
ARMOR_STAND(ArmorStandEntity.class, 61, 1.975f, 0.5f),
|
||||||
TRIPOD_CAMERA(Entity.class, 62, 0f),
|
TRIPOD_CAMERA(Entity.class, 62, 0f),
|
||||||
PLAYER(PlayerEntity.class, 63, 1.8f, 0.6f, 0.6f, 1.62f),
|
PLAYER(PlayerEntity.class, 63, 1.8f, 0.6f, 0.6f, 1.62f),
|
||||||
ITEM(ItemEntity.class, 64, 0.25f, 0.25f),
|
ITEM(ItemEntity.class, 64, 0.25f, 0.25f),
|
||||||
TNT(Entity.class, 65, 0.98f, 0.98f),
|
PRIMED_TNT(TNTEntity.class, 65, 0.98f, 0.98f, 0.98f, 0f, "minecraft:tnt"),
|
||||||
FALLING_BLOCK(FallingBlockEntity.class, 66, 0.98f, 0.98f),
|
FALLING_BLOCK(FallingBlockEntity.class, 66, 0.98f, 0.98f),
|
||||||
MOVING_BLOCK(Entity.class, 67, 0f),
|
MOVING_BLOCK(Entity.class, 67, 0f),
|
||||||
EXPERIENCE_BOTTLE(ThrowableEntity.class, 68, 0.25f, 0.25f),
|
THROWN_EXP_BOTTLE(ThrowableEntity.class, 68, 0.25f, 0.25f, 0f, 0f, "minecraft:xp_bottle"),
|
||||||
EXPERIENCE_ORB(ExpOrbEntity.class, 69, 0f),
|
EXPERIENCE_ORB(ExpOrbEntity.class, 69, 0f, 0f, 0f, 0f, "minecraft:xp_orb"),
|
||||||
EYE_OF_ENDER(Entity.class, 70, 0f),
|
EYE_OF_ENDER(Entity.class, 70, 0.25f, 0.25f, 0f, 0f, "minecraft:eye_of_ender_signal"),
|
||||||
END_CRYSTAL(EnderCrystalEntity.class, 71, 0f),
|
END_CRYSTAL(EnderCrystalEntity.class, 71, 2.0f, 2.0f, 2.0f, 0f, "minecraft:ender_crystal"),
|
||||||
FIREWORK_ROCKET(Entity.class, 72, 0f),
|
FIREWORK_ROCKET(FireworkEntity.class, 72, 0.25f, 0.25f, 0.25f, 0f, "minecraft:fireworks_rocket"),
|
||||||
TRIDENT(ArrowEntity.class, 73, 0f),
|
TRIDENT(TridentEntity.class, 73, 0f, 0f, 0f, 0f, "minecraft:thrown_trident"),
|
||||||
TURTLE(AnimalEntity.class, 74, 0.4f, 1.2f),
|
TURTLE(AnimalEntity.class, 74, 0.4f, 1.2f),
|
||||||
CAT(CatEntity.class, 75, 0.35f, 0.3f),
|
CAT(CatEntity.class, 75, 0.35f, 0.3f),
|
||||||
SHULKER_BULLET(Entity.class, 76, 0f),
|
SHULKER_BULLET(Entity.class, 76, 0.3125f),
|
||||||
FISHING_BOBBER(FishingHookEntity.class, 77, 0f),
|
FISHING_BOBBER(FishingHookEntity.class, 77, 0f, 0f, 0f, 0f, "minecraft:fishing_hook"),
|
||||||
CHALKBOARD(Entity.class, 78, 0f),
|
CHALKBOARD(Entity.class, 78, 0f),
|
||||||
DRAGON_FIREBALL(ItemedFireballEntity.class, 79, 0f),
|
DRAGON_FIREBALL(ItemedFireballEntity.class, 79, 1.0f),
|
||||||
ARROW(ArrowEntity.class, 80, 0.25f, 0.25f),
|
ARROW(TippedArrowEntity.class, 80, 0.25f, 0.25f),
|
||||||
SNOWBALL(ThrowableEntity.class, 81, 0f),
|
SPECTRAL_ARROW(AbstractArrowEntity.class, 80, 0.25f, 0.25f, 0.25f, 0f, "minecraft:arrow"),
|
||||||
EGG(ThrowableEntity.class, 82, 0f),
|
SNOWBALL(ThrowableEntity.class, 81, 0.25f),
|
||||||
|
THROWN_EGG(ThrowableEntity.class, 82, 0.25f, 0.25f, 0.25f, 0f, "minecraft:egg"),
|
||||||
PAINTING(PaintingEntity.class, 83, 0f),
|
PAINTING(PaintingEntity.class, 83, 0f),
|
||||||
MINECART(MinecartEntity.class, 84, 0f),
|
MINECART(MinecartEntity.class, 84, 0.7f, 0.98f, 0.98f, 0.35f),
|
||||||
FIREBALL(ItemedFireballEntity.class, 85, 0f),
|
FIREBALL(ItemedFireballEntity.class, 85, 1.0f),
|
||||||
POTION(ThrowableEntity.class, 86, 0f),
|
THROWN_POTION(ThrowableEntity.class, 86, 0.25f, 0.25f, 0.25f, 0f, "minecraft:splash_potion"),
|
||||||
ENDER_PEARL(ThrowableEntity.class, 87, 0f),
|
THROWN_ENDERPEARL(ThrowableEntity.class, 87, 0.25f, 0.25f, 0.25f, 0f, "minecraft:ender_pearl"),
|
||||||
LEASH_KNOT(Entity.class, 88, 0f),
|
LEASH_KNOT(LeashKnotEntity.class, 88, 0.5f, 0.375f),
|
||||||
WITHER_SKULL(Entity.class, 89, 0f),
|
WITHER_SKULL(Entity.class, 89, 0.3125f),
|
||||||
BOAT(Entity.class, 90, 0.7f, 1.6f, 1.6f, 0.35f),
|
BOAT(BoatEntity.class, 90, 0.7f, 1.6f, 1.6f, 0.35f),
|
||||||
WITHER_SKULL_DANGEROUS(Entity.class, 91, 0f),
|
WITHER_SKULL_DANGEROUS(Entity.class, 91, 0f),
|
||||||
LIGHTNING_BOLT(Entity.class, 93, 0f),
|
LIGHTNING_BOLT(Entity.class, 93, 0f),
|
||||||
SMALL_FIREBALL(ItemedFireballEntity.class, 94, 0f),
|
SMALL_FIREBALL(ItemedFireballEntity.class, 94, 0.3125f),
|
||||||
AREA_EFFECT_CLOUD(Entity.class, 95, 0f),
|
AREA_EFFECT_CLOUD(AreaEffectCloudEntity.class, 95, 0.5f, 1.0f),
|
||||||
HOPPER_MINECART(MinecartEntity.class, 96, 0f),
|
MINECART_HOPPER(MinecartEntity.class, 96, 0.7f, 0.98f, 0.98f, 0.35f, "minecraft:hopper_minecart"),
|
||||||
TNT_MINECART(MinecartEntity.class, 97, 0f),
|
MINECART_TNT(MinecartEntity.class, 97, 0.7f, 0.98f, 0.98f, 0.35f, "minecraft:tnt_minecart"),
|
||||||
CHEST_MINECART(MinecartEntity.class, 98, 0f),
|
MINECART_CHEST(MinecartEntity.class, 98, 0.7f, 0.98f, 0.98f, 0.35f, "minecraft:chest_minecart"),
|
||||||
|
MINECART_FURNACE(FurnaceMinecartEntity.class, 98, 0.7f, 0.98f, 0.98f, 0.35f, "minecraft:minecart"),
|
||||||
COMMAND_BLOCK_MINECART(MinecartEntity.class, 100, 0f),
|
MINECART_COMMAND_BLOCK(MinecartEntity.class, 100, 0.7f, 0.98f, 0.98f, 0.35f, "minecraft:command_block_minecart"),
|
||||||
LINGERING_POTION(ThrowableEntity.class, 101, 0f),
|
LINGERING_POTION(ThrowableEntity.class, 101, 0f),
|
||||||
LLAMA_SPIT(Entity.class, 102, 0f),
|
LLAMA_SPIT(Entity.class, 102, 0.25f),
|
||||||
EVOKER_FANGS(Entity.class, 103, 0f),
|
EVOKER_FANGS(Entity.class, 103, 0.8f, 0.5f),
|
||||||
EVOKER(SpellcasterIllagerEntity.class, 104, 0f),
|
EVOKER(SpellcasterIllagerEntity.class, 104, 1.95f, 0.5f),
|
||||||
VEX(MonsterEntity.class, 105, 0f),
|
VEX(MonsterEntity.class, 105, 0.8f, 0.4f),
|
||||||
ICE_BOMB(Entity.class, 106, 0f),
|
ICE_BOMB(Entity.class, 106, 0f),
|
||||||
BALLOON(Entity.class, 107, 0f), //TODO
|
BALLOON(Entity.class, 107, 0f), //TODO
|
||||||
PUFFERFISH(PufferFishEntity.class, 108, 0.7f, 0.7f),
|
PUFFERFISH(PufferFishEntity.class, 108, 0.7f, 0.7f),
|
||||||
SALMON(AbstractFishEntity.class, 109, 0.5f, 0.7f),
|
SALMON(AbstractFishEntity.class, 109, 0.5f, 0.7f),
|
||||||
DROWNED(ZombieEntity.class, 110, 1.95f, 0.6f),
|
DROWNED(ZombieEntity.class, 110, 1.95f, 0.6f),
|
||||||
TROPICAL_FISH(TropicalFishEntity.class, 111, 0.6f, 0.6f),
|
TROPICAL_FISH(TropicalFishEntity.class, 111, 0.6f, 0.6f, 0f, 0f, "minecraft:tropicalfish"),
|
||||||
COD(AbstractFishEntity.class, 112, 0.25f, 0.5f),
|
COD(AbstractFishEntity.class, 112, 0.25f, 0.5f),
|
||||||
PANDA(PandaEntity.class, 113, 1.25f, 1.125f, 1.825f),
|
PANDA(PandaEntity.class, 113, 1.25f, 1.125f, 1.825f),
|
||||||
FOX(FoxEntity.class, 121, 0.5f, 1.25f),
|
FOX(FoxEntity.class, 121, 0.5f, 1.25f),
|
||||||
BEE(BeeEntity.class, 122, 0.6f, 0.6f);
|
BEE(BeeEntity.class, 122, 0.6f, 0.6f),
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Item frames are handled differently since they are a block in Bedrock.
|
||||||
|
*/
|
||||||
|
ITEM_FRAME(ItemFrameEntity.class, 0, 0, 0),
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Not an entity in Bedrock, so we replace it with a Pillager
|
||||||
|
*/
|
||||||
|
ILLUSIONER(AbstractIllagerEntity.class, 114, 1.8f, 0.6f, 0.6f, 1.62f, "minecraft:pillager");
|
||||||
|
|
||||||
|
private static final EntityType[] VALUES = values();
|
||||||
|
|
||||||
private Class<? extends Entity> entityClass;
|
private Class<? extends Entity> entityClass;
|
||||||
private final int type;
|
private final int type;
|
||||||
|
@ -155,9 +169,10 @@ public enum EntityType {
|
||||||
private final float width;
|
private final float width;
|
||||||
private final float length;
|
private final float length;
|
||||||
private final float offset;
|
private final float offset;
|
||||||
|
private String identifier;
|
||||||
|
|
||||||
EntityType(Class<? extends Entity> entityClass, int type, float height) {
|
EntityType(Class<? extends Entity> entityClass, int type, float height) {
|
||||||
this(entityClass, type, height, 0f);
|
this(entityClass, type, height, height);
|
||||||
}
|
}
|
||||||
|
|
||||||
EntityType(Class<? extends Entity> entityClass, int type, float height, float width) {
|
EntityType(Class<? extends Entity> entityClass, int type, float height, float width) {
|
||||||
|
@ -169,11 +184,28 @@ public enum EntityType {
|
||||||
}
|
}
|
||||||
|
|
||||||
EntityType(Class<? extends Entity> entityClass, int type, float height, float width, float length, float offset) {
|
EntityType(Class<? extends Entity> entityClass, int type, float height, float width, float length, float offset) {
|
||||||
|
this(entityClass, type, height, width, length, offset, null);
|
||||||
|
|
||||||
|
this.identifier = "minecraft:" + name().toLowerCase();
|
||||||
|
}
|
||||||
|
|
||||||
|
EntityType(Class<? extends Entity> entityClass, int type, float height, float width, float length, float offset, String identifier) {
|
||||||
this.entityClass = entityClass;
|
this.entityClass = entityClass;
|
||||||
this.type = type;
|
this.type = type;
|
||||||
this.height = height;
|
this.height = height;
|
||||||
this.width = width;
|
this.width = width;
|
||||||
this.length = length;
|
this.length = length;
|
||||||
this.offset = offset + 0.00001f;
|
this.offset = offset + 0.00001f;
|
||||||
|
this.identifier = identifier;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static EntityType getFromIdentifier(String identifier) {
|
||||||
|
for (EntityType type : VALUES) {
|
||||||
|
if (type.identifier.equals(identifier)) {
|
||||||
|
return type;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -25,12 +25,13 @@
|
||||||
|
|
||||||
package org.geysermc.connector.network;
|
package org.geysermc.connector.network;
|
||||||
|
|
||||||
import com.github.steveice10.mc.protocol.data.status.ServerStatusInfo;
|
import com.github.steveice10.mc.protocol.data.message.Message;
|
||||||
import com.nukkitx.protocol.bedrock.BedrockPong;
|
import com.nukkitx.protocol.bedrock.*;
|
||||||
import com.nukkitx.protocol.bedrock.BedrockServerEventHandler;
|
import io.netty.channel.ChannelHandlerContext;
|
||||||
import com.nukkitx.protocol.bedrock.BedrockServerSession;
|
import io.netty.channel.socket.DatagramPacket;
|
||||||
|
import org.geysermc.common.ping.GeyserPingInfo;
|
||||||
import org.geysermc.common.IGeyserConfiguration;
|
import org.geysermc.connector.ping.IGeyserPingPassthrough;
|
||||||
|
import org.geysermc.connector.GeyserConfiguration;
|
||||||
import org.geysermc.connector.GeyserConnector;
|
import org.geysermc.connector.GeyserConnector;
|
||||||
import org.geysermc.connector.network.session.GeyserSession;
|
import org.geysermc.connector.network.session.GeyserSession;
|
||||||
import org.geysermc.connector.utils.MessageUtils;
|
import org.geysermc.connector.utils.MessageUtils;
|
||||||
|
@ -39,7 +40,7 @@ import java.net.InetSocketAddress;
|
||||||
|
|
||||||
public class ConnectorServerEventHandler implements BedrockServerEventHandler {
|
public class ConnectorServerEventHandler implements BedrockServerEventHandler {
|
||||||
|
|
||||||
private GeyserConnector connector;
|
private final GeyserConnector connector;
|
||||||
|
|
||||||
public ConnectorServerEventHandler(GeyserConnector connector) {
|
public ConnectorServerEventHandler(GeyserConnector connector) {
|
||||||
this.connector = connector;
|
this.connector = connector;
|
||||||
|
@ -55,30 +56,40 @@ public class ConnectorServerEventHandler implements BedrockServerEventHandler {
|
||||||
public BedrockPong onQuery(InetSocketAddress inetSocketAddress) {
|
public BedrockPong onQuery(InetSocketAddress inetSocketAddress) {
|
||||||
connector.getLogger().debug(inetSocketAddress + " has pinged you!");
|
connector.getLogger().debug(inetSocketAddress + " has pinged you!");
|
||||||
|
|
||||||
IGeyserConfiguration config = connector.getConfig();
|
GeyserConfiguration config = connector.getConfig();
|
||||||
ServerStatusInfo serverInfo = connector.getPassthroughThread().getInfo();
|
|
||||||
|
GeyserPingInfo pingInfo = null;
|
||||||
|
if (config.isPassthroughMotd() || config.isPassthroughPlayerCounts()) {
|
||||||
|
IGeyserPingPassthrough pingPassthrough = connector.getBootstrap().getGeyserPingPassthrough();
|
||||||
|
pingInfo = pingPassthrough.getPingInformation();
|
||||||
|
}
|
||||||
|
|
||||||
BedrockPong pong = new BedrockPong();
|
BedrockPong pong = new BedrockPong();
|
||||||
pong.setEdition("MCPE");
|
pong.setEdition("MCPE");
|
||||||
pong.setGameType("Default");
|
pong.setGameType("Default");
|
||||||
pong.setNintendoLimited(false);
|
pong.setNintendoLimited(false);
|
||||||
pong.setProtocolVersion(GeyserConnector.BEDROCK_PACKET_CODEC.getProtocolVersion());
|
pong.setProtocolVersion(GeyserConnector.BEDROCK_PACKET_CODEC.getProtocolVersion());
|
||||||
pong.setVersion(GeyserConnector.BEDROCK_PACKET_CODEC.getMinecraftVersion());
|
pong.setVersion(null); // Server tries to connect either way and it looks better
|
||||||
pong.setIpv4Port(config.getBedrock().getPort());
|
pong.setIpv4Port(config.getBedrock().getPort());
|
||||||
if (connector.getConfig().isPingPassthrough() && serverInfo != null) {
|
|
||||||
String[] motd = MessageUtils.getBedrockMessage(serverInfo.getDescription()).split("\n");
|
if (config.isPassthroughMotd() && pingInfo != null && pingInfo.motd != null) {
|
||||||
|
String[] motd = MessageUtils.getBedrockMessage(Message.fromString(pingInfo.motd)).split("\n");
|
||||||
String mainMotd = motd[0]; // First line of the motd.
|
String mainMotd = motd[0]; // First line of the motd.
|
||||||
String subMotd = (motd.length != 1) ? motd[1] : ""; // Second line of the motd if present, otherwise blank.
|
String subMotd = (motd.length != 1) ? motd[1] : ""; // Second line of the motd if present, otherwise blank.
|
||||||
|
|
||||||
pong.setMotd(mainMotd.trim());
|
pong.setMotd(mainMotd.trim());
|
||||||
pong.setSubMotd(subMotd.trim()); // Trimmed to shift it to the left, prevents the universe from collapsing on us just because we went 2 characters over the text box's limit.
|
pong.setSubMotd(subMotd.trim()); // Trimmed to shift it to the left, prevents the universe from collapsing on us just because we went 2 characters over the text box's limit.
|
||||||
pong.setPlayerCount(serverInfo.getPlayerInfo().getOnlinePlayers());
|
} else {
|
||||||
pong.setMaximumPlayerCount(serverInfo.getPlayerInfo().getMaxPlayers());
|
pong.setMotd(config.getBedrock().getMotd1());
|
||||||
|
pong.setSubMotd(config.getBedrock().getMotd2());
|
||||||
|
}
|
||||||
|
|
||||||
|
if (config.isPassthroughPlayerCounts() && pingInfo != null) {
|
||||||
|
pong.setPlayerCount(pingInfo.currentPlayerCount);
|
||||||
|
pong.setMaximumPlayerCount(pingInfo.maxPlayerCount);
|
||||||
} else {
|
} else {
|
||||||
pong.setPlayerCount(connector.getPlayers().size());
|
pong.setPlayerCount(connector.getPlayers().size());
|
||||||
pong.setMaximumPlayerCount(config.getMaxPlayers());
|
pong.setMaximumPlayerCount(config.getMaxPlayers());
|
||||||
pong.setMotd(config.getBedrock().getMotd1());
|
|
||||||
pong.setMotd(config.getBedrock().getMotd2());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//Bedrock will not even attempt a connection if the client thinks the server is full
|
//Bedrock will not even attempt a connection if the client thinks the server is full
|
||||||
|
@ -101,13 +112,13 @@ public class ConnectorServerEventHandler implements BedrockServerEventHandler {
|
||||||
if (player != null) {
|
if (player != null) {
|
||||||
player.disconnect(disconnectReason.name());
|
player.disconnect(disconnectReason.name());
|
||||||
connector.removePlayer(player);
|
connector.removePlayer(player);
|
||||||
|
|
||||||
player.getEntityCache().clear();
|
|
||||||
player.getInventoryCache().getInventories().clear();
|
|
||||||
player.getWindowCache().getWindows().clear();
|
|
||||||
player.getScoreboardCache().removeScoreboard();
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
bedrockServerSession.setPacketCodec(GeyserConnector.BEDROCK_PACKET_CODEC);
|
bedrockServerSession.setPacketCodec(GeyserConnector.BEDROCK_PACKET_CODEC);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onUnhandledDatagram(ChannelHandlerContext ctx, DatagramPacket packet) {
|
||||||
|
new QueryPacketHandler(connector, packet.sender(), packet.content());
|
||||||
|
}
|
||||||
}
|
}
|
|
@ -0,0 +1,268 @@
|
||||||
|
/*
|
||||||
|
* 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.connector.network;
|
||||||
|
|
||||||
|
import com.github.steveice10.mc.protocol.data.message.Message;
|
||||||
|
import io.netty.buffer.ByteBuf;
|
||||||
|
import io.netty.buffer.ByteBufAllocator;
|
||||||
|
import org.geysermc.common.ping.GeyserPingInfo;
|
||||||
|
import org.geysermc.connector.GeyserConnector;
|
||||||
|
import org.geysermc.connector.utils.MessageUtils;
|
||||||
|
|
||||||
|
import java.io.ByteArrayOutputStream;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.net.InetAddress;
|
||||||
|
import java.net.InetSocketAddress;
|
||||||
|
import java.nio.ByteBuffer;
|
||||||
|
import java.nio.charset.StandardCharsets;
|
||||||
|
import java.security.MessageDigest;
|
||||||
|
import java.security.NoSuchAlgorithmException;
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.Random;
|
||||||
|
import java.util.concurrent.ThreadLocalRandom;
|
||||||
|
|
||||||
|
public class QueryPacketHandler {
|
||||||
|
|
||||||
|
public static final byte HANDSHAKE = 0x09;
|
||||||
|
public static final byte STATISTICS = 0x00;
|
||||||
|
|
||||||
|
private GeyserConnector connector;
|
||||||
|
private InetSocketAddress sender;
|
||||||
|
private byte type;
|
||||||
|
private int sessionId;
|
||||||
|
private byte[] token;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The Query packet handler instance
|
||||||
|
* @param connector Geyser Connector
|
||||||
|
* @param sender The Sender IP/Port for the Query
|
||||||
|
* @param buffer The Query data
|
||||||
|
*/
|
||||||
|
public QueryPacketHandler(GeyserConnector connector, InetSocketAddress sender, ByteBuf buffer) {
|
||||||
|
if(!isQueryPacket(buffer))
|
||||||
|
return;
|
||||||
|
|
||||||
|
this.connector = connector;
|
||||||
|
this.sender = sender;
|
||||||
|
this.type = buffer.readByte();
|
||||||
|
this.sessionId = buffer.readInt();
|
||||||
|
|
||||||
|
regenerateToken();
|
||||||
|
handle();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks the packet is in fact a query packet
|
||||||
|
* @param buffer Query data
|
||||||
|
* @return if the packet is a query packet
|
||||||
|
*/
|
||||||
|
private boolean isQueryPacket(ByteBuf buffer) {
|
||||||
|
return (buffer.readableBytes() >= 2) ? buffer.readUnsignedShort() == 65277 : false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handles the query
|
||||||
|
*/
|
||||||
|
private void handle() {
|
||||||
|
switch (type) {
|
||||||
|
case HANDSHAKE:
|
||||||
|
sendToken();
|
||||||
|
case STATISTICS:
|
||||||
|
sendQueryData();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sends the token to the sender
|
||||||
|
*/
|
||||||
|
private void sendToken() {
|
||||||
|
ByteBuf reply = ByteBufAllocator.DEFAULT.ioBuffer(10);
|
||||||
|
reply.writeByte(HANDSHAKE);
|
||||||
|
reply.writeInt(sessionId);
|
||||||
|
reply.writeBytes(getTokenString(this.token, this.sender.getAddress()));
|
||||||
|
reply.writeByte(0);
|
||||||
|
|
||||||
|
sendPacket(reply);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sends the query data to the sender
|
||||||
|
*/
|
||||||
|
private void sendQueryData() {
|
||||||
|
ByteBuf reply = ByteBufAllocator.DEFAULT.ioBuffer(64);
|
||||||
|
reply.writeByte(STATISTICS);
|
||||||
|
reply.writeInt(sessionId);
|
||||||
|
|
||||||
|
// Game Info
|
||||||
|
reply.writeBytes(getGameData());
|
||||||
|
|
||||||
|
// Players
|
||||||
|
reply.writeBytes(getPlayers());
|
||||||
|
|
||||||
|
sendPacket(reply);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the game data for the query
|
||||||
|
* @return the game data for the query
|
||||||
|
*/
|
||||||
|
private byte[] getGameData() {
|
||||||
|
ByteArrayOutputStream query = new ByteArrayOutputStream();
|
||||||
|
|
||||||
|
GeyserPingInfo pingInfo = null;
|
||||||
|
String motd;
|
||||||
|
String currentPlayerCount;
|
||||||
|
String maxPlayerCount;
|
||||||
|
|
||||||
|
if (connector.getConfig().isPassthroughMotd() || connector.getConfig().isPassthroughPlayerCounts()) {
|
||||||
|
pingInfo = connector.getBootstrap().getGeyserPingPassthrough().getPingInformation();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (connector.getConfig().isPassthroughMotd() && pingInfo != null) {
|
||||||
|
String[] javaMotd = MessageUtils.getBedrockMessage(Message.fromString(pingInfo.motd)).split("\n");
|
||||||
|
motd = javaMotd[0].trim(); // First line of the motd.
|
||||||
|
} else {
|
||||||
|
motd = connector.getConfig().getBedrock().getMotd1();
|
||||||
|
}
|
||||||
|
|
||||||
|
// If passthrough player counts is enabled lets get players from the server
|
||||||
|
if (connector.getConfig().isPassthroughPlayerCounts() && pingInfo != null) {
|
||||||
|
currentPlayerCount = String.valueOf(pingInfo.currentPlayerCount);
|
||||||
|
maxPlayerCount = String.valueOf(pingInfo.maxPlayerCount);
|
||||||
|
} else {
|
||||||
|
currentPlayerCount = String.valueOf(connector.getPlayers().size());
|
||||||
|
maxPlayerCount = String.valueOf(connector.getConfig().getMaxPlayers());
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create a hashmap of all game data needed in the query
|
||||||
|
Map<String, String> gameData = new HashMap<String, String>();
|
||||||
|
gameData.put("hostname", motd);
|
||||||
|
gameData.put("gametype", "SMP");
|
||||||
|
gameData.put("game_id", "MINECRAFT");
|
||||||
|
gameData.put("version", GeyserConnector.BEDROCK_PACKET_CODEC.getMinecraftVersion());
|
||||||
|
gameData.put("plugins", "");
|
||||||
|
gameData.put("map", GeyserConnector.NAME);
|
||||||
|
gameData.put("numplayers", currentPlayerCount);
|
||||||
|
gameData.put("maxplayers", maxPlayerCount);
|
||||||
|
gameData.put("hostport", String.valueOf(connector.getConfig().getBedrock().getPort()));
|
||||||
|
gameData.put("hostip", connector.getConfig().getBedrock().getAddress());
|
||||||
|
|
||||||
|
try {
|
||||||
|
// Blank Buffer Bytes
|
||||||
|
query.write("GeyserMC".getBytes());
|
||||||
|
query.write((byte) 0x00);
|
||||||
|
query.write((byte) 128);
|
||||||
|
query.write((byte) 0x00);
|
||||||
|
|
||||||
|
// Fills the game data
|
||||||
|
for(Map.Entry<String, String> entry : gameData.entrySet()) {
|
||||||
|
query.write(entry.getKey().getBytes());
|
||||||
|
query.write((byte) 0x00);
|
||||||
|
query.write(entry.getValue().getBytes());
|
||||||
|
query.write((byte) 0x00);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Final byte to show the end of the game data
|
||||||
|
query.write(new byte[]{0x00, 0x01});
|
||||||
|
return query.toByteArray();
|
||||||
|
} catch (IOException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
return new byte[0];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private byte[] getPlayers() {
|
||||||
|
ByteArrayOutputStream query = new ByteArrayOutputStream();
|
||||||
|
|
||||||
|
GeyserPingInfo pingInfo = null;
|
||||||
|
if (connector.getConfig().isPassthroughMotd() || connector.getConfig().isPassthroughPlayerCounts()) {
|
||||||
|
pingInfo = connector.getBootstrap().getGeyserPingPassthrough().getPingInformation();
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
// Start the player section
|
||||||
|
query.write("player_".getBytes());
|
||||||
|
query.write(new byte[]{0x00, 0x00});
|
||||||
|
|
||||||
|
// Fill player names
|
||||||
|
if(pingInfo != null) {
|
||||||
|
for (String username : pingInfo.getPlayers()) {
|
||||||
|
query.write(username.getBytes());
|
||||||
|
query.write((byte) 0x00);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Final byte to show the end of the player data
|
||||||
|
query.write((byte) 0x00);
|
||||||
|
return query.toByteArray();
|
||||||
|
} catch (IOException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
return new byte[0];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sends a packet to the sender
|
||||||
|
* @param data packet data
|
||||||
|
*/
|
||||||
|
private void sendPacket(ByteBuf data) {
|
||||||
|
connector.getBedrockServer().getRakNet().send(sender, data);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Regenerates a token
|
||||||
|
*/
|
||||||
|
public void regenerateToken() {
|
||||||
|
byte[] token = new byte[16];
|
||||||
|
for (int i = 0; i < 16; i++) {
|
||||||
|
token[i] = (byte) new Random().nextInt(255);
|
||||||
|
}
|
||||||
|
|
||||||
|
this.token = token;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets an MD5 token for the current IP/Port.
|
||||||
|
* This should reset every 30 seconds but a new one is generated per instance
|
||||||
|
* Seems wasteful to code something in to clear it when it has no use.
|
||||||
|
* @param token the token
|
||||||
|
* @param address the address
|
||||||
|
* @return an MD5 token for the current IP/Port
|
||||||
|
*/
|
||||||
|
public static byte[] getTokenString(byte[] token, InetAddress address) {
|
||||||
|
try {
|
||||||
|
MessageDigest digest = MessageDigest.getInstance("MD5");
|
||||||
|
digest.update(address.toString().getBytes(StandardCharsets.UTF_8));
|
||||||
|
digest.update(token);
|
||||||
|
return Arrays.copyOf(digest.digest(), 4);
|
||||||
|
} catch (NoSuchAlgorithmException e) {
|
||||||
|
return ByteBuffer.allocate(4).putInt(ThreadLocalRandom.current().nextInt()).array();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -28,15 +28,15 @@ package org.geysermc.connector.network;
|
||||||
import com.nukkitx.protocol.bedrock.BedrockPacket;
|
import com.nukkitx.protocol.bedrock.BedrockPacket;
|
||||||
import com.nukkitx.protocol.bedrock.packet.*;
|
import com.nukkitx.protocol.bedrock.packet.*;
|
||||||
import org.geysermc.common.AuthType;
|
import org.geysermc.common.AuthType;
|
||||||
import org.geysermc.common.IGeyserConfiguration;
|
import org.geysermc.connector.GeyserConfiguration;
|
||||||
import org.geysermc.connector.GeyserConnector;
|
import org.geysermc.connector.GeyserConnector;
|
||||||
import org.geysermc.connector.network.session.GeyserSession;
|
import org.geysermc.connector.network.session.GeyserSession;
|
||||||
import org.geysermc.connector.network.translators.Registry;
|
|
||||||
import org.geysermc.connector.utils.*;
|
import org.geysermc.connector.utils.*;
|
||||||
|
import org.geysermc.connector.network.translators.PacketTranslatorRegistry;
|
||||||
|
import org.geysermc.connector.utils.LoginEncryptionUtils;
|
||||||
|
|
||||||
import java.io.FileInputStream;
|
import java.io.FileInputStream;
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
import java.util.UUID;
|
|
||||||
|
|
||||||
public class UpstreamPacketHandler extends LoggingPacketHandler {
|
public class UpstreamPacketHandler extends LoggingPacketHandler {
|
||||||
|
|
||||||
|
@ -45,7 +45,7 @@ public class UpstreamPacketHandler extends LoggingPacketHandler {
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean translateAndDefault(BedrockPacket packet) {
|
private boolean translateAndDefault(BedrockPacket packet) {
|
||||||
return Registry.BEDROCK.translate(packet.getClass(), packet, session);
|
return PacketTranslatorRegistry.BEDROCK_TRANSLATOR.translate(packet.getClass(), packet, session);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -62,7 +62,7 @@ public class UpstreamPacketHandler extends LoggingPacketHandler {
|
||||||
|
|
||||||
PlayStatusPacket playStatus = new PlayStatusPacket();
|
PlayStatusPacket playStatus = new PlayStatusPacket();
|
||||||
playStatus.setStatus(PlayStatusPacket.Status.LOGIN_SUCCESS);
|
playStatus.setStatus(PlayStatusPacket.Status.LOGIN_SUCCESS);
|
||||||
session.getUpstream().sendPacket(playStatus);
|
session.sendUpstreamPacket(playStatus);
|
||||||
|
|
||||||
ResourcePacksInfoPacket resourcePacksInfo = new ResourcePacksInfoPacket();
|
ResourcePacksInfoPacket resourcePacksInfo = new ResourcePacksInfoPacket();
|
||||||
for(ResourcePack resourcePack : ResourcePack.PACKS.values()) {
|
for(ResourcePack resourcePack : ResourcePack.PACKS.values()) {
|
||||||
|
@ -71,7 +71,7 @@ public class UpstreamPacketHandler extends LoggingPacketHandler {
|
||||||
resourcePacksInfo.getResourcePackInfos().add(new ResourcePacksInfoPacket.Entry(header.getUuid().toString(), version, resourcePack.getFile().length(), "", "", "", false));
|
resourcePacksInfo.getResourcePackInfos().add(new ResourcePacksInfoPacket.Entry(header.getUuid().toString(), version, resourcePack.getFile().length(), "", "", "", false));
|
||||||
}
|
}
|
||||||
resourcePacksInfo.setForcedToAccept(true);
|
resourcePacksInfo.setForcedToAccept(true);
|
||||||
session.getUpstream().sendPacket(resourcePacksInfo);
|
session.sendUpstreamPacket(resourcePacksInfo);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -110,7 +110,7 @@ public class UpstreamPacketHandler extends LoggingPacketHandler {
|
||||||
String version = header.getVersion()[0] + "." + header.getVersion()[1] + "." + header.getVersion()[2];
|
String version = header.getVersion()[0] + "." + header.getVersion()[1] + "." + header.getVersion()[2];
|
||||||
stackPacket.getResourcePacks().add(new ResourcePackStackPacket.Entry(header.getUuid().toString(), version, ""));
|
stackPacket.getResourcePacks().add(new ResourcePackStackPacket.Entry(header.getUuid().toString(), version, ""));
|
||||||
}
|
}
|
||||||
session.getUpstream().sendPacket(stackPacket);
|
session.sendUpstreamPacket(stackPacket);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
|
@ -128,7 +128,7 @@ public class UpstreamPacketHandler extends LoggingPacketHandler {
|
||||||
|
|
||||||
private boolean couldLoginUserByName(String bedrockUsername) {
|
private boolean couldLoginUserByName(String bedrockUsername) {
|
||||||
if (connector.getConfig().getUserAuths() != null) {
|
if (connector.getConfig().getUserAuths() != null) {
|
||||||
IGeyserConfiguration.IUserAuthenticationInfo info = connector.getConfig().getUserAuths().get(bedrockUsername);
|
GeyserConfiguration.IUserAuthenticationInfo info = connector.getConfig().getUserAuths().get(bedrockUsername);
|
||||||
|
|
||||||
if (info != null) {
|
if (info != null) {
|
||||||
connector.getLogger().info("using stored credentials for bedrock user " + session.getAuthData().getName());
|
connector.getLogger().info("using stored credentials for bedrock user " + session.getAuthData().getName());
|
||||||
|
@ -144,15 +144,19 @@ public class UpstreamPacketHandler extends LoggingPacketHandler {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean handle(MovePlayerPacket packet) {
|
public boolean handle(SetLocalPlayerAsInitializedPacket packet) {
|
||||||
if (!session.isLoggedIn() && !session.isLoggingIn() && session.getConnector().getAuthType() == AuthType.ONLINE) {
|
if (!session.isLoggedIn() && !session.isLoggingIn() && session.getConnector().getAuthType() == AuthType.ONLINE) {
|
||||||
// TODO it is safer to key authentication on something that won't change (UUID, not username)
|
// TODO it is safer to key authentication on something that won't change (UUID, not username)
|
||||||
if (!couldLoginUserByName(session.getAuthData().getName())) {
|
if (!couldLoginUserByName(session.getAuthData().getName())) {
|
||||||
LoginEncryptionUtils.showLoginWindow(session);
|
LoginEncryptionUtils.showLoginWindow(session);
|
||||||
}
|
}
|
||||||
// else we were able to log the user in
|
// else we were able to log the user in
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
return translateAndDefault(packet);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean handle(MovePlayerPacket packet) {
|
||||||
if (session.isLoggingIn()) {
|
if (session.isLoggingIn()) {
|
||||||
session.sendMessage("Please wait until you are logged in...");
|
session.sendMessage("Please wait until you are logged in...");
|
||||||
}
|
}
|
||||||
|
|
|
@ -29,42 +29,50 @@ import com.github.steveice10.mc.auth.data.GameProfile;
|
||||||
import com.github.steveice10.mc.auth.exception.request.InvalidCredentialsException;
|
import com.github.steveice10.mc.auth.exception.request.InvalidCredentialsException;
|
||||||
import com.github.steveice10.mc.auth.exception.request.RequestException;
|
import com.github.steveice10.mc.auth.exception.request.RequestException;
|
||||||
import com.github.steveice10.mc.protocol.MinecraftProtocol;
|
import com.github.steveice10.mc.protocol.MinecraftProtocol;
|
||||||
|
import com.github.steveice10.mc.protocol.data.SubProtocol;
|
||||||
import com.github.steveice10.mc.protocol.data.game.entity.player.GameMode;
|
import com.github.steveice10.mc.protocol.data.game.entity.player.GameMode;
|
||||||
|
import com.github.steveice10.mc.protocol.data.game.world.block.BlockState;
|
||||||
import com.github.steveice10.mc.protocol.packet.handshake.client.HandshakePacket;
|
import com.github.steveice10.mc.protocol.packet.handshake.client.HandshakePacket;
|
||||||
|
import com.github.steveice10.mc.protocol.packet.ingame.client.world.ClientTeleportConfirmPacket;
|
||||||
import com.github.steveice10.mc.protocol.packet.ingame.server.ServerRespawnPacket;
|
import com.github.steveice10.mc.protocol.packet.ingame.server.ServerRespawnPacket;
|
||||||
|
import com.github.steveice10.mc.protocol.packet.login.server.LoginSuccessPacket;
|
||||||
import com.github.steveice10.packetlib.Client;
|
import com.github.steveice10.packetlib.Client;
|
||||||
import com.github.steveice10.packetlib.event.session.*;
|
import com.github.steveice10.packetlib.event.session.*;
|
||||||
import com.github.steveice10.packetlib.packet.Packet;
|
import com.github.steveice10.packetlib.packet.Packet;
|
||||||
import com.github.steveice10.packetlib.tcp.TcpSessionFactory;
|
import com.github.steveice10.packetlib.tcp.TcpSessionFactory;
|
||||||
import com.nukkitx.math.GenericMath;
|
import com.nukkitx.math.GenericMath;
|
||||||
import com.nukkitx.math.TrigMath;
|
import com.nukkitx.math.TrigMath;
|
||||||
import com.nukkitx.math.vector.Vector2f;
|
import com.nukkitx.math.vector.*;
|
||||||
import com.nukkitx.math.vector.Vector2i;
|
import com.nukkitx.protocol.bedrock.BedrockPacket;
|
||||||
import com.nukkitx.math.vector.Vector3f;
|
|
||||||
import com.nukkitx.math.vector.Vector3i;
|
|
||||||
import com.nukkitx.protocol.bedrock.BedrockServerSession;
|
import com.nukkitx.protocol.bedrock.BedrockServerSession;
|
||||||
import com.nukkitx.protocol.bedrock.data.ContainerId;
|
import com.nukkitx.protocol.bedrock.data.ContainerId;
|
||||||
import com.nukkitx.protocol.bedrock.data.GamePublishSetting;
|
import com.nukkitx.protocol.bedrock.data.GamePublishSetting;
|
||||||
import com.nukkitx.protocol.bedrock.data.GameRuleData;
|
import com.nukkitx.protocol.bedrock.data.GameRuleData;
|
||||||
import com.nukkitx.protocol.bedrock.data.PlayerPermission;
|
import com.nukkitx.protocol.bedrock.data.PlayerPermission;
|
||||||
import com.nukkitx.protocol.bedrock.packet.*;
|
import com.nukkitx.protocol.bedrock.packet.*;
|
||||||
|
import it.unimi.dsi.fastutil.objects.Object2LongMap;
|
||||||
|
import it.unimi.dsi.fastutil.objects.Object2LongOpenHashMap;
|
||||||
import lombok.Getter;
|
import lombok.Getter;
|
||||||
import lombok.Setter;
|
import lombok.Setter;
|
||||||
import org.geysermc.common.AuthType;
|
import org.geysermc.common.AuthType;
|
||||||
import org.geysermc.common.window.FormWindow;
|
import org.geysermc.common.window.FormWindow;
|
||||||
import org.geysermc.connector.GeyserConnector;
|
import org.geysermc.connector.GeyserConnector;
|
||||||
import org.geysermc.connector.command.CommandSender;
|
import org.geysermc.connector.command.CommandSender;
|
||||||
|
import org.geysermc.connector.entity.Entity;
|
||||||
import org.geysermc.connector.entity.PlayerEntity;
|
import org.geysermc.connector.entity.PlayerEntity;
|
||||||
import org.geysermc.connector.inventory.PlayerInventory;
|
import org.geysermc.connector.inventory.PlayerInventory;
|
||||||
import org.geysermc.connector.network.remote.RemoteServer;
|
import org.geysermc.connector.network.remote.RemoteServer;
|
||||||
import org.geysermc.connector.network.session.auth.AuthData;
|
import org.geysermc.connector.network.session.auth.AuthData;
|
||||||
import org.geysermc.connector.network.session.auth.BedrockClientData;
|
import org.geysermc.connector.network.session.auth.BedrockClientData;
|
||||||
import org.geysermc.connector.network.session.cache.*;
|
import org.geysermc.connector.network.session.cache.*;
|
||||||
import org.geysermc.connector.network.translators.Registry;
|
import org.geysermc.connector.network.translators.BiomeTranslator;
|
||||||
import org.geysermc.connector.network.translators.block.BlockTranslator;
|
import org.geysermc.connector.network.translators.EntityIdentifierRegistry;
|
||||||
|
import org.geysermc.connector.network.translators.PacketTranslatorRegistry;
|
||||||
|
import org.geysermc.connector.network.translators.item.ItemRegistry;
|
||||||
|
import org.geysermc.connector.network.translators.world.block.BlockTranslator;
|
||||||
import org.geysermc.connector.utils.ChunkUtils;
|
import org.geysermc.connector.utils.ChunkUtils;
|
||||||
import org.geysermc.connector.utils.LocaleUtils;
|
import org.geysermc.connector.utils.LocaleUtils;
|
||||||
import org.geysermc.connector.utils.Toolbox;
|
import org.geysermc.connector.utils.SkinUtils;
|
||||||
import org.geysermc.floodgate.util.BedrockData;
|
import org.geysermc.floodgate.util.BedrockData;
|
||||||
import org.geysermc.floodgate.util.EncryptionUtil;
|
import org.geysermc.floodgate.util.EncryptionUtil;
|
||||||
|
|
||||||
|
@ -83,8 +91,10 @@ public class GeyserSession implements CommandSender {
|
||||||
private final UpstreamSession upstream;
|
private final UpstreamSession upstream;
|
||||||
private RemoteServer remoteServer;
|
private RemoteServer remoteServer;
|
||||||
private Client downstream;
|
private Client downstream;
|
||||||
@Setter private AuthData authData;
|
@Setter
|
||||||
@Setter private BedrockClientData clientData;
|
private AuthData authData;
|
||||||
|
@Setter
|
||||||
|
private BedrockClientData clientData;
|
||||||
|
|
||||||
private PlayerEntity playerEntity;
|
private PlayerEntity playerEntity;
|
||||||
private PlayerInventory inventory;
|
private PlayerInventory inventory;
|
||||||
|
@ -94,6 +104,14 @@ public class GeyserSession implements CommandSender {
|
||||||
private InventoryCache inventoryCache;
|
private InventoryCache inventoryCache;
|
||||||
private ScoreboardCache scoreboardCache;
|
private ScoreboardCache scoreboardCache;
|
||||||
private WindowCache windowCache;
|
private WindowCache windowCache;
|
||||||
|
@Setter
|
||||||
|
private TeleportCache teleportCache;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A map of Vector3i positions to Java entity IDs.
|
||||||
|
* Used for translating Bedrock block actions to Java entity actions.
|
||||||
|
*/
|
||||||
|
private final Object2LongMap<Vector3i> itemFrameCache = new Object2LongOpenHashMap<>();
|
||||||
|
|
||||||
private DataCache<Packet> javaPacketCache;
|
private DataCache<Packet> javaPacketCache;
|
||||||
|
|
||||||
|
@ -112,20 +130,47 @@ public class GeyserSession implements CommandSender {
|
||||||
private GameMode gameMode = GameMode.SURVIVAL;
|
private GameMode gameMode = GameMode.SURVIVAL;
|
||||||
|
|
||||||
private final AtomicInteger pendingDimSwitches = new AtomicInteger(0);
|
private final AtomicInteger pendingDimSwitches = new AtomicInteger(0);
|
||||||
|
|
||||||
|
@Setter
|
||||||
|
private boolean sneaking;
|
||||||
|
|
||||||
@Setter
|
@Setter
|
||||||
private boolean sprinting;
|
private boolean sprinting;
|
||||||
|
|
||||||
@Setter
|
@Setter
|
||||||
private boolean jumping;
|
private boolean jumping;
|
||||||
|
|
||||||
|
@Setter
|
||||||
|
private BlockState breakingBlock;
|
||||||
|
|
||||||
|
@Setter
|
||||||
|
private Vector3i lastBlockPlacePosition;
|
||||||
|
|
||||||
|
@Setter
|
||||||
|
private String lastBlockPlacedId;
|
||||||
|
|
||||||
|
@Setter
|
||||||
|
private boolean interacting;
|
||||||
|
|
||||||
|
@Setter
|
||||||
|
private Vector3i lastInteractionPosition;
|
||||||
|
|
||||||
@Setter
|
@Setter
|
||||||
private boolean switchingDimension = false;
|
private boolean switchingDimension = false;
|
||||||
private boolean manyDimPackets = false;
|
private boolean manyDimPackets = false;
|
||||||
private ServerRespawnPacket lastDimPacket = null;
|
private ServerRespawnPacket lastDimPacket = null;
|
||||||
|
|
||||||
|
@Setter
|
||||||
|
private Entity ridingVehicleEntity;
|
||||||
|
|
||||||
@Setter
|
@Setter
|
||||||
private int craftSlot = 0;
|
private int craftSlot = 0;
|
||||||
|
|
||||||
|
@Setter
|
||||||
|
private long lastWindowCloseTime = 0;
|
||||||
|
|
||||||
|
private MinecraftProtocol protocol;
|
||||||
|
|
||||||
public GeyserSession(GeyserConnector connector, BedrockServerSession bedrockServerSession) {
|
public GeyserSession(GeyserConnector connector, BedrockServerSession bedrockServerSession) {
|
||||||
this.connector = connector;
|
this.connector = connector;
|
||||||
this.upstream = new UpstreamSession(bedrockServerSession);
|
this.upstream = new UpstreamSession(bedrockServerSession);
|
||||||
|
@ -154,16 +199,16 @@ public class GeyserSession implements CommandSender {
|
||||||
ChunkUtils.sendEmptyChunks(this, playerEntity.getPosition().toInt(), 0, false);
|
ChunkUtils.sendEmptyChunks(this, playerEntity.getPosition().toInt(), 0, false);
|
||||||
|
|
||||||
BiomeDefinitionListPacket biomeDefinitionListPacket = new BiomeDefinitionListPacket();
|
BiomeDefinitionListPacket biomeDefinitionListPacket = new BiomeDefinitionListPacket();
|
||||||
biomeDefinitionListPacket.setTag(Toolbox.BIOMES);
|
biomeDefinitionListPacket.setTag(BiomeTranslator.BIOMES);
|
||||||
upstream.sendPacket(biomeDefinitionListPacket);
|
upstream.sendPacket(biomeDefinitionListPacket);
|
||||||
|
|
||||||
AvailableEntityIdentifiersPacket entityPacket = new AvailableEntityIdentifiersPacket();
|
AvailableEntityIdentifiersPacket entityPacket = new AvailableEntityIdentifiersPacket();
|
||||||
entityPacket.setTag(Toolbox.ENTITY_IDENTIFIERS);
|
entityPacket.setTag(EntityIdentifierRegistry.ENTITY_IDENTIFIERS);
|
||||||
upstream.sendPacket(entityPacket);
|
upstream.sendPacket(entityPacket);
|
||||||
|
|
||||||
InventoryContentPacket creativePacket = new InventoryContentPacket();
|
InventoryContentPacket creativePacket = new InventoryContentPacket();
|
||||||
creativePacket.setContainerId(ContainerId.CREATIVE);
|
creativePacket.setContainerId(ContainerId.CREATIVE);
|
||||||
creativePacket.setContents(Toolbox.CREATIVE_ITEMS);
|
creativePacket.setContents(ItemRegistry.CREATIVE_ITEMS);
|
||||||
upstream.sendPacket(creativePacket);
|
upstream.sendPacket(creativePacket);
|
||||||
|
|
||||||
PlayStatusPacket playStatusPacket = new PlayStatusPacket();
|
PlayStatusPacket playStatusPacket = new PlayStatusPacket();
|
||||||
|
@ -171,6 +216,17 @@ public class GeyserSession implements CommandSender {
|
||||||
upstream.sendPacket(playStatusPacket);
|
upstream.sendPacket(playStatusPacket);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void fetchOurSkin(PlayerListPacket.Entry entry) {
|
||||||
|
PlayerSkinPacket playerSkinPacket = new PlayerSkinPacket();
|
||||||
|
playerSkinPacket.setUuid(authData.getUUID());
|
||||||
|
playerSkinPacket.setSkin(entry.getSkin());
|
||||||
|
playerSkinPacket.setOldSkinName("OldName");
|
||||||
|
playerSkinPacket.setNewSkinName("NewName");
|
||||||
|
playerSkinPacket.setTrustedSkin(true);
|
||||||
|
upstream.sendPacket(playerSkinPacket);
|
||||||
|
getConnector().getLogger().debug("Sending skin for " + playerEntity.getUsername() + " " + authData.getUUID());
|
||||||
|
}
|
||||||
|
|
||||||
public void login() {
|
public void login() {
|
||||||
if (connector.getAuthType() != AuthType.ONLINE) {
|
if (connector.getAuthType() != AuthType.ONLINE) {
|
||||||
connector.getLogger().info(
|
connector.getLogger().info(
|
||||||
|
@ -197,7 +253,6 @@ public class GeyserSession implements CommandSender {
|
||||||
// new thread so clients don't timeout
|
// new thread so clients don't timeout
|
||||||
new Thread(() -> {
|
new Thread(() -> {
|
||||||
try {
|
try {
|
||||||
MinecraftProtocol protocol;
|
|
||||||
if (password != null && !password.isEmpty()) {
|
if (password != null && !password.isEmpty()) {
|
||||||
protocol = new MinecraftProtocol(username, password);
|
protocol = new MinecraftProtocol(username, password);
|
||||||
} else {
|
} else {
|
||||||
|
@ -295,13 +350,33 @@ public class GeyserSession implements CommandSender {
|
||||||
lastDimPacket = event.getPacket();
|
lastDimPacket = event.getPacket();
|
||||||
return;
|
return;
|
||||||
} else if (lastDimPacket != null) {
|
} else if (lastDimPacket != null) {
|
||||||
Registry.JAVA.translate(lastDimPacket.getClass(), lastDimPacket, GeyserSession.this);
|
PacketTranslatorRegistry.JAVA_TRANSLATOR.translate(lastDimPacket.getClass(), lastDimPacket, GeyserSession.this);
|
||||||
lastDimPacket = null;
|
lastDimPacket = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
Registry.JAVA.translate(event.getPacket().getClass(), event.getPacket(), GeyserSession.this);
|
// Required, or else Floodgate players break with Bukkit chunk caching
|
||||||
|
if (event.getPacket() instanceof LoginSuccessPacket) {
|
||||||
|
GameProfile profile = ((LoginSuccessPacket) event.getPacket()).getProfile();
|
||||||
|
playerEntity.setUsername(profile.getName());
|
||||||
|
playerEntity.setUuid(profile.getId());
|
||||||
|
|
||||||
|
// Check if they are not using a linked account
|
||||||
|
if (connector.getAuthType() == AuthType.OFFLINE || playerEntity.getUuid().getMostSignificantBits() == 0) {
|
||||||
|
SkinUtils.handleBedrockSkin(playerEntity, clientData);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
PacketTranslatorRegistry.JAVA_TRANSLATOR.translate(event.getPacket().getClass(), event.getPacket(), GeyserSession.this);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void packetError(PacketErrorEvent event) {
|
||||||
|
connector.getLogger().warning("Downstream packet error! " + event.getCause().getMessage());
|
||||||
|
if (connector.getConfig().isDebugMode())
|
||||||
|
event.getCause().printStackTrace();
|
||||||
|
event.setSuppress(true);
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
downstream.getSession().connect();
|
downstream.getSession().connect();
|
||||||
|
@ -327,10 +402,11 @@ public class GeyserSession implements CommandSender {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
this.entityCache.getEntities().clear();
|
this.chunkCache = null;
|
||||||
this.scoreboardCache.removeScoreboard();
|
this.entityCache = null;
|
||||||
this.inventoryCache.getInventories().clear();
|
this.scoreboardCache = null;
|
||||||
this.windowCache.getWindows().clear();
|
this.inventoryCache = null;
|
||||||
|
this.windowCache = null;
|
||||||
|
|
||||||
closed = true;
|
closed = true;
|
||||||
}
|
}
|
||||||
|
@ -434,9 +510,63 @@ public class GeyserSession implements CommandSender {
|
||||||
startGamePacket.setEnchantmentSeed(0);
|
startGamePacket.setEnchantmentSeed(0);
|
||||||
startGamePacket.setMultiplayerCorrelationId("");
|
startGamePacket.setMultiplayerCorrelationId("");
|
||||||
startGamePacket.setBlockPalette(BlockTranslator.BLOCKS);
|
startGamePacket.setBlockPalette(BlockTranslator.BLOCKS);
|
||||||
startGamePacket.setItemEntries(Toolbox.ITEMS);
|
startGamePacket.setItemEntries(ItemRegistry.ITEMS);
|
||||||
startGamePacket.setVanillaVersion("*");
|
startGamePacket.setVanillaVersion("*");
|
||||||
// startGamePacket.setMovementServerAuthoritative(true);
|
// startGamePacket.setMovementServerAuthoritative(true);
|
||||||
upstream.sendPacketImmediately(startGamePacket);
|
upstream.sendPacketImmediately(startGamePacket);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public boolean confirmTeleport(Vector3d position) {
|
||||||
|
if (teleportCache != null) {
|
||||||
|
if (!teleportCache.canConfirm(position)) {
|
||||||
|
GeyserConnector.getInstance().getLogger().debug("Unconfirmed Teleport " + teleportCache.getTeleportConfirmId()
|
||||||
|
+ " Ignore movement " + position + " expected " + teleportCache);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
int teleportId = teleportCache.getTeleportConfirmId();
|
||||||
|
teleportCache = null;
|
||||||
|
ClientTeleportConfirmPacket teleportConfirmPacket = new ClientTeleportConfirmPacket(teleportId);
|
||||||
|
sendDownstreamPacket(teleportConfirmPacket);
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Queue a packet to be sent to player.
|
||||||
|
*
|
||||||
|
* @param packet the bedrock packet from the NukkitX protocol lib
|
||||||
|
*/
|
||||||
|
public void sendUpstreamPacket(BedrockPacket packet) {
|
||||||
|
if (upstream != null && !upstream.isClosed()) {
|
||||||
|
upstream.sendPacket(packet);
|
||||||
|
} else {
|
||||||
|
connector.getLogger().debug("Tried to send upstream packet " + packet.getClass().getSimpleName() + " but the session was null");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Send a packet immediately to the player.
|
||||||
|
*
|
||||||
|
* @param packet the bedrock packet from the NukkitX protocol lib
|
||||||
|
*/
|
||||||
|
public void sendUpstreamPacketImmediately(BedrockPacket packet) {
|
||||||
|
if (upstream != null && !upstream.isClosed()) {
|
||||||
|
upstream.sendPacketImmediately(packet);
|
||||||
|
} else {
|
||||||
|
connector.getLogger().debug("Tried to send upstream packet " + packet.getClass().getSimpleName() + " immediately but the session was null");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Send a packet to the remote server.
|
||||||
|
*
|
||||||
|
* @param packet the java edition packet from MCProtocolLib
|
||||||
|
*/
|
||||||
|
public void sendDownstreamPacket(Packet packet) {
|
||||||
|
if (downstream != null && downstream.getSession() != null && protocol.getSubProtocol().equals(SubProtocol.GAME)) {
|
||||||
|
downstream.getSession().send(packet);
|
||||||
|
} else {
|
||||||
|
connector.getLogger().debug("Tried to send downstream packet " + packet.getClass().getSimpleName() + " before connected to the server");
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -24,16 +24,26 @@ public class BedrockClientData {
|
||||||
private String skinId;
|
private String skinId;
|
||||||
@JsonProperty(value = "SkinData")
|
@JsonProperty(value = "SkinData")
|
||||||
private String skinData;
|
private String skinData;
|
||||||
|
@JsonProperty(value = "SkinImageHeight")
|
||||||
|
private int skinImageHeight;
|
||||||
|
@JsonProperty(value = "SkinImageWidth")
|
||||||
|
private int skinImageWidth;
|
||||||
@JsonProperty(value = "CapeId")
|
@JsonProperty(value = "CapeId")
|
||||||
private String capeId;
|
private String capeId;
|
||||||
@JsonProperty(value = "CapeData")
|
@JsonProperty(value = "CapeData")
|
||||||
private byte[] capeData;
|
private byte[] capeData;
|
||||||
|
@JsonProperty(value = "CapeImageHeight")
|
||||||
|
private int capeImageHeight;
|
||||||
|
@JsonProperty(value = "CapeImageWidth")
|
||||||
|
private int capeImageWidth;
|
||||||
@JsonProperty(value = "CapeOnClassicSkin")
|
@JsonProperty(value = "CapeOnClassicSkin")
|
||||||
private boolean capeOnClassicSkin;
|
private boolean capeOnClassicSkin;
|
||||||
@JsonProperty(value = "SkinResourcePatch")
|
@JsonProperty(value = "SkinResourcePatch")
|
||||||
private String geometryName;
|
private String geometryName;
|
||||||
@JsonProperty(value = "SkinGeometryData")
|
@JsonProperty(value = "SkinGeometryData")
|
||||||
private String geometryData;
|
private String geometryData;
|
||||||
|
@JsonProperty(value = "PersonaSkin")
|
||||||
|
private boolean personaSkin;
|
||||||
@JsonProperty(value = "PremiumSkin")
|
@JsonProperty(value = "PremiumSkin")
|
||||||
private boolean premiumSkin;
|
private boolean premiumSkin;
|
||||||
|
|
||||||
|
@ -60,6 +70,15 @@ public class BedrockClientData {
|
||||||
@JsonProperty(value = "ClientRandomId")
|
@JsonProperty(value = "ClientRandomId")
|
||||||
private long clientRandomId;
|
private long clientRandomId;
|
||||||
|
|
||||||
|
@JsonProperty(value = "ArmSize")
|
||||||
|
private String armSize;
|
||||||
|
@JsonProperty(value = "SkinAnimationData")
|
||||||
|
private String skinAnimationData;
|
||||||
|
@JsonProperty(value = "SkinColor")
|
||||||
|
private String skinColor;
|
||||||
|
@JsonProperty(value = "ThirdPartyNameOnly")
|
||||||
|
private boolean thirdPartyNameOnly;
|
||||||
|
|
||||||
public enum UIProfile {
|
public enum UIProfile {
|
||||||
@JsonEnumDefaultValue
|
@JsonEnumDefaultValue
|
||||||
CLASSIC,
|
CLASSIC,
|
||||||
|
|
|
@ -62,7 +62,7 @@ public class BossBar {
|
||||||
bossEventPacket.setOverlay(overlay);
|
bossEventPacket.setOverlay(overlay);
|
||||||
bossEventPacket.setDarkenSky(darkenSky);
|
bossEventPacket.setDarkenSky(darkenSky);
|
||||||
|
|
||||||
session.getUpstream().sendPacket(bossEventPacket);
|
session.sendUpstreamPacket(bossEventPacket);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void updateTitle(Message title) {
|
public void updateTitle(Message title) {
|
||||||
|
@ -72,7 +72,7 @@ public class BossBar {
|
||||||
bossEventPacket.setAction(BossEventPacket.Action.TITLE);
|
bossEventPacket.setAction(BossEventPacket.Action.TITLE);
|
||||||
bossEventPacket.setTitle(MessageUtils.getTranslatedBedrockMessage(title, session.getClientData().getLanguageCode()));
|
bossEventPacket.setTitle(MessageUtils.getTranslatedBedrockMessage(title, session.getClientData().getLanguageCode()));
|
||||||
|
|
||||||
session.getUpstream().sendPacket(bossEventPacket);
|
session.sendUpstreamPacket(bossEventPacket);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void updateHealth(float health) {
|
public void updateHealth(float health) {
|
||||||
|
@ -82,7 +82,7 @@ public class BossBar {
|
||||||
bossEventPacket.setAction(BossEventPacket.Action.HEALTH_PERCENTAGE);
|
bossEventPacket.setAction(BossEventPacket.Action.HEALTH_PERCENTAGE);
|
||||||
bossEventPacket.setHealthPercentage(health);
|
bossEventPacket.setHealthPercentage(health);
|
||||||
|
|
||||||
session.getUpstream().sendPacket(bossEventPacket);
|
session.sendUpstreamPacket(bossEventPacket);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void removeBossBar() {
|
public void removeBossBar() {
|
||||||
|
@ -90,7 +90,7 @@ public class BossBar {
|
||||||
bossEventPacket.setBossUniqueEntityId(entityId);
|
bossEventPacket.setBossUniqueEntityId(entityId);
|
||||||
bossEventPacket.setAction(BossEventPacket.Action.HIDE);
|
bossEventPacket.setAction(BossEventPacket.Action.HIDE);
|
||||||
|
|
||||||
session.getUpstream().sendPacket(bossEventPacket);
|
session.sendUpstreamPacket(bossEventPacket);
|
||||||
removeBossEntity();
|
removeBossEntity();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -104,18 +104,21 @@ public class BossBar {
|
||||||
addEntityPacket.setRuntimeEntityId(entityId);
|
addEntityPacket.setRuntimeEntityId(entityId);
|
||||||
addEntityPacket.setIdentifier("minecraft:creeper");
|
addEntityPacket.setIdentifier("minecraft:creeper");
|
||||||
addEntityPacket.setEntityType(33);
|
addEntityPacket.setEntityType(33);
|
||||||
addEntityPacket.setPosition(session.getPlayerEntity().getPosition());
|
addEntityPacket.setPosition(session.getPlayerEntity().getPosition().sub(0D, -10D, 0D));
|
||||||
addEntityPacket.setRotation(Vector3f.ZERO);
|
addEntityPacket.setRotation(Vector3f.ZERO);
|
||||||
addEntityPacket.setMotion(Vector3f.ZERO);
|
addEntityPacket.setMotion(Vector3f.ZERO);
|
||||||
addEntityPacket.getMetadata().put(EntityData.SCALE, 0.01F); // scale = 0 doesn't work?
|
addEntityPacket.getMetadata()
|
||||||
|
.putFloat(EntityData.SCALE, 0F)
|
||||||
|
.putFloat(EntityData.BOUNDING_BOX_WIDTH, 0F)
|
||||||
|
.putFloat(EntityData.BOUNDING_BOX_HEIGHT, 0F);
|
||||||
|
|
||||||
session.getUpstream().sendPacket(addEntityPacket);
|
session.sendUpstreamPacket(addEntityPacket);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void removeBossEntity() {
|
private void removeBossEntity() {
|
||||||
RemoveEntityPacket removeEntityPacket = new RemoveEntityPacket();
|
RemoveEntityPacket removeEntityPacket = new RemoveEntityPacket();
|
||||||
removeEntityPacket.setUniqueEntityId(entityId);
|
removeEntityPacket.setUniqueEntityId(entityId);
|
||||||
|
|
||||||
session.getUpstream().sendPacket(removeEntityPacket);
|
session.sendUpstreamPacket(removeEntityPacket);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -29,34 +29,39 @@ import com.github.steveice10.mc.protocol.data.game.chunk.Chunk;
|
||||||
import com.github.steveice10.mc.protocol.data.game.chunk.Column;
|
import com.github.steveice10.mc.protocol.data.game.chunk.Column;
|
||||||
import com.github.steveice10.mc.protocol.data.game.entity.metadata.Position;
|
import com.github.steveice10.mc.protocol.data.game.entity.metadata.Position;
|
||||||
import com.github.steveice10.mc.protocol.data.game.world.block.BlockState;
|
import com.github.steveice10.mc.protocol.data.game.world.block.BlockState;
|
||||||
import com.nukkitx.protocol.bedrock.packet.LevelChunkPacket;
|
|
||||||
import lombok.Getter;
|
import lombok.Getter;
|
||||||
import org.geysermc.connector.network.session.GeyserSession;
|
import org.geysermc.connector.network.session.GeyserSession;
|
||||||
import org.geysermc.connector.network.translators.Translators;
|
import org.geysermc.connector.network.translators.world.block.BlockTranslator;
|
||||||
import org.geysermc.connector.network.translators.block.BlockTranslator;
|
import org.geysermc.connector.network.translators.world.chunk.ChunkPosition;
|
||||||
import org.geysermc.connector.world.chunk.ChunkPosition;
|
|
||||||
|
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
public class ChunkCache {
|
public class ChunkCache {
|
||||||
|
|
||||||
private GeyserSession session;
|
private boolean cache;
|
||||||
|
private final GeyserSession session;
|
||||||
|
|
||||||
@Getter
|
@Getter
|
||||||
private Map<ChunkPosition, Column> chunks;
|
private Map<ChunkPosition, Column> chunks = new HashMap<>();
|
||||||
|
|
||||||
public ChunkCache(GeyserSession session) {
|
public ChunkCache(GeyserSession session) {
|
||||||
this.session = session;
|
this.session = session;
|
||||||
this.chunks = new HashMap<>();
|
this.cache = session.getConnector().getConfig().isCacheChunks();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void addToCache(Column chunk) {
|
public void addToCache(Column chunk) {
|
||||||
|
if (!cache) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
ChunkPosition position = new ChunkPosition(chunk.getX(), chunk.getZ());
|
ChunkPosition position = new ChunkPosition(chunk.getX(), chunk.getZ());
|
||||||
chunks.put(position, chunk);
|
chunks.put(position, chunk);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void updateBlock(Position position, BlockState block) {
|
public void updateBlock(Position position, BlockState block) {
|
||||||
|
if (!cache) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
ChunkPosition chunkPosition = new ChunkPosition(position.getX() >> 4, position.getZ() >> 4);
|
ChunkPosition chunkPosition = new ChunkPosition(position.getX() >> 4, position.getZ() >> 4);
|
||||||
if (!chunks.containsKey(chunkPosition))
|
if (!chunks.containsKey(chunkPosition))
|
||||||
return;
|
return;
|
||||||
|
@ -70,6 +75,9 @@ public class ChunkCache {
|
||||||
}
|
}
|
||||||
|
|
||||||
public BlockState getBlockAt(Position position) {
|
public BlockState getBlockAt(Position position) {
|
||||||
|
if (!cache) {
|
||||||
|
return BlockTranslator.AIR;
|
||||||
|
}
|
||||||
ChunkPosition chunkPosition = new ChunkPosition(position.getX() >> 4, position.getZ() >> 4);
|
ChunkPosition chunkPosition = new ChunkPosition(position.getX() >> 4, position.getZ() >> 4);
|
||||||
if (!chunks.containsKey(chunkPosition))
|
if (!chunks.containsKey(chunkPosition))
|
||||||
return BlockTranslator.AIR;
|
return BlockTranslator.AIR;
|
||||||
|
@ -85,24 +93,9 @@ public class ChunkCache {
|
||||||
}
|
}
|
||||||
|
|
||||||
public void removeChunk(ChunkPosition position) {
|
public void removeChunk(ChunkPosition position) {
|
||||||
chunks.remove(position);
|
if (!cache) {
|
||||||
sendEmptyChunk(position, true);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void sendEmptyChunk(ChunkPosition position) {
|
|
||||||
sendEmptyChunk(position, false);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void sendEmptyChunk(ChunkPosition position, boolean force) {
|
|
||||||
if (!force && chunks.containsKey(position))
|
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
LevelChunkPacket levelChunkPacket = new LevelChunkPacket();
|
chunks.remove(position);
|
||||||
levelChunkPacket.setChunkX(position.getX());
|
|
||||||
levelChunkPacket.setChunkZ(position.getZ());
|
|
||||||
levelChunkPacket.setCachingEnabled(false);
|
|
||||||
levelChunkPacket.setSubChunksLength(0);
|
|
||||||
levelChunkPacket.setData(Translators.EMPTY_LEVEL_CHUNK_DATA);
|
|
||||||
session.getUpstream().sendPacket(levelChunkPacket);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -26,8 +26,6 @@
|
||||||
package org.geysermc.connector.network.session.cache;
|
package org.geysermc.connector.network.session.cache;
|
||||||
|
|
||||||
import it.unimi.dsi.fastutil.longs.*;
|
import it.unimi.dsi.fastutil.longs.*;
|
||||||
import it.unimi.dsi.fastutil.objects.Object2LongMap;
|
|
||||||
import it.unimi.dsi.fastutil.objects.Object2LongOpenHashMap;
|
|
||||||
import it.unimi.dsi.fastutil.objects.ObjectOpenHashSet;
|
import it.unimi.dsi.fastutil.objects.ObjectOpenHashSet;
|
||||||
import lombok.Getter;
|
import lombok.Getter;
|
||||||
import org.geysermc.connector.entity.Entity;
|
import org.geysermc.connector.entity.Entity;
|
||||||
|
@ -49,6 +47,7 @@ public class EntityCache {
|
||||||
private Long2LongMap entityIdTranslations = Long2LongMaps.synchronize(new Long2LongOpenHashMap());
|
private Long2LongMap entityIdTranslations = Long2LongMaps.synchronize(new Long2LongOpenHashMap());
|
||||||
private Map<UUID, PlayerEntity> playerEntities = Collections.synchronizedMap(new HashMap<>());
|
private Map<UUID, PlayerEntity> playerEntities = Collections.synchronizedMap(new HashMap<>());
|
||||||
private Map<UUID, BossBar> bossBars = Collections.synchronizedMap(new HashMap<>());
|
private Map<UUID, BossBar> bossBars = Collections.synchronizedMap(new HashMap<>());
|
||||||
|
private Long2LongMap cachedPlayerEntityLinks = Long2LongMaps.synchronize(new Long2LongOpenHashMap());
|
||||||
|
|
||||||
@Getter
|
@Getter
|
||||||
private AtomicLong nextEntityId = new AtomicLong(2L);
|
private AtomicLong nextEntityId = new AtomicLong(2L);
|
||||||
|
@ -148,4 +147,12 @@ public class EntityCache {
|
||||||
playerEntities = null;
|
playerEntities = null;
|
||||||
bossBars = null;
|
bossBars = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public long getCachedPlayerEntityLink(long playerId) {
|
||||||
|
return cachedPlayerEntityLinks.getOrDefault(playerId, -1);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void addCachedPlayerEntityLink(long playerId, long linkedEntityId) {
|
||||||
|
cachedPlayerEntityLinks.put(playerId, linkedEntityId);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -23,31 +23,26 @@
|
||||||
* @link https://github.com/GeyserMC/Geyser
|
* @link https://github.com/GeyserMC/Geyser
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package org.geysermc.connector.world.chunk;
|
package org.geysermc.connector.network.session.cache;
|
||||||
|
|
||||||
import com.github.steveice10.mc.protocol.data.game.entity.metadata.Position;
|
import com.nukkitx.math.vector.Vector3d;
|
||||||
|
import com.nukkitx.math.vector.Vector3f;
|
||||||
import lombok.AllArgsConstructor;
|
import lombok.AllArgsConstructor;
|
||||||
import lombok.EqualsAndHashCode;
|
import lombok.Data;
|
||||||
import lombok.Getter;
|
|
||||||
import lombok.Setter;
|
|
||||||
|
|
||||||
@Getter
|
|
||||||
@Setter
|
|
||||||
@AllArgsConstructor
|
@AllArgsConstructor
|
||||||
@EqualsAndHashCode
|
@Data
|
||||||
public class ChunkPosition {
|
public class TeleportCache {
|
||||||
|
|
||||||
private int x;
|
private static final double ERROR = 0.2;
|
||||||
private int z;
|
private static final double ERROR_Y = 0.5;
|
||||||
|
|
||||||
public Position getBlock(int x, int y, int z) {
|
private double x, y, z;
|
||||||
return new Position((this.x << 4) + x, y, (this.z << 4) + z);
|
private int teleportConfirmId;
|
||||||
}
|
|
||||||
|
|
||||||
public Position getChunkBlock(int x, int y, int z) {
|
public boolean canConfirm(Vector3d position) {
|
||||||
int chunkX = x & 15;
|
return (Math.abs(this.x - position.getX()) < ERROR &&
|
||||||
int chunkY = y & 15;
|
Math.abs(this.y - position.getY()) < ERROR_Y &&
|
||||||
int chunkZ = z & 15;
|
Math.abs(this.z - position.getZ()) < ERROR);
|
||||||
return new Position(chunkX, chunkY, chunkZ);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -66,7 +66,7 @@ public class WindowCache {
|
||||||
formRequestPacket.setFormId(id);
|
formRequestPacket.setFormId(id);
|
||||||
formRequestPacket.setFormData(windows.get(id).getJSONData());
|
formRequestPacket.setFormData(windows.get(id).getJSONData());
|
||||||
|
|
||||||
session.getUpstream().sendPacket(formRequestPacket);
|
session.sendUpstreamPacket(formRequestPacket);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void showWindow(FormWindow window, int id) {
|
public void showWindow(FormWindow window, int id) {
|
||||||
|
@ -74,7 +74,7 @@ public class WindowCache {
|
||||||
formRequestPacket.setFormId(id);
|
formRequestPacket.setFormId(id);
|
||||||
formRequestPacket.setFormData(window.getJSONData());
|
formRequestPacket.setFormData(window.getJSONData());
|
||||||
|
|
||||||
session.getUpstream().sendPacket(formRequestPacket);
|
session.sendUpstreamPacket(formRequestPacket);
|
||||||
|
|
||||||
addWindow(window, id);
|
addWindow(window, id);
|
||||||
}
|
}
|
||||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue