mirror of
https://github.com/GeyserMC/Geyser.git
synced 2024-12-12 09:50:49 +01:00
commit
6df89ed679
296 changed files with 15346 additions and 7750 deletions
2
.github/FUNDING.yml
vendored
2
.github/FUNDING.yml
vendored
|
@ -1,7 +1,7 @@
|
||||||
# These are supported funding model platforms
|
# These are supported funding model platforms
|
||||||
|
|
||||||
github: # Replace with up to 4 GitHub Sponsors-enabled usernames e.g., [user1, user2]
|
github: # Replace with up to 4 GitHub Sponsors-enabled usernames e.g., [user1, user2]
|
||||||
patreon: GeyserMC
|
patreon: #GeyserMC # Disabled currently
|
||||||
open_collective: # Replace with a single Open Collective username
|
open_collective: # Replace with a single Open Collective username
|
||||||
ko_fi: # Replace with a single Ko-fi username
|
ko_fi: # Replace with a single Ko-fi username
|
||||||
tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel
|
tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel
|
||||||
|
|
1
.gitignore
vendored
1
.gitignore
vendored
|
@ -243,3 +243,4 @@ public-key.pem
|
||||||
locales/
|
locales/
|
||||||
/cache/
|
/cache/
|
||||||
/packs/
|
/packs/
|
||||||
|
/dump.json
|
1
Jenkinsfile
vendored
1
Jenkinsfile
vendored
|
@ -24,6 +24,7 @@ pipeline {
|
||||||
when {
|
when {
|
||||||
branch "master"
|
branch "master"
|
||||||
}
|
}
|
||||||
|
|
||||||
steps {
|
steps {
|
||||||
sh 'mvn javadoc:jar source:jar deploy -DskipTests'
|
sh 'mvn javadoc:jar source:jar deploy -DskipTests'
|
||||||
}
|
}
|
||||||
|
|
30
README.md
30
README.md
|
@ -18,7 +18,7 @@ The ultimate goal of this project is to allow Minecraft: Bedrock Edition users t
|
||||||
|
|
||||||
Special thanks to the DragonProxy project for being a trailblazer in protocol translation and for all the team members who have now joined us here!
|
Special thanks to the DragonProxy project for being a trailblazer in protocol translation and for all the team members who have now joined us here!
|
||||||
|
|
||||||
### Currently supporting Minecraft Bedrock v1.16.x and Minecraft Java v1.16.3.
|
### Currently supporting Minecraft Bedrock v1.16.100/v1.16.101/v1.16.200 and Minecraft Java v1.16.4.
|
||||||
|
|
||||||
## Setting Up
|
## Setting Up
|
||||||
Take a look [here](https://github.com/GeyserMC/Geyser/wiki#Setup) for how to set up Geyser.
|
Take a look [here](https://github.com/GeyserMC/Geyser/wiki#Setup) for how to set up Geyser.
|
||||||
|
@ -34,16 +34,26 @@ Take a look [here](https://github.com/GeyserMC/Geyser/wiki#Setup) for how to set
|
||||||
- Test Server: `test.geysermc.org` port `25565` for Java and `19132` for Bedrock
|
- Test Server: `test.geysermc.org` port `25565` for Java and `19132` for Bedrock
|
||||||
|
|
||||||
## What's Left to be Added/Fixed
|
## What's Left to be Added/Fixed
|
||||||
- The Following Inventories
|
- Lecterns
|
||||||
- [ ] Enchantment Table (as a proper GUI)
|
- Near-perfect movement (to the point where anticheat on large servers is unlikely to ban you)
|
||||||
- [ ] Beacon
|
- Resource pack conversion/CustomModelData
|
||||||
- [ ] Cartography Table
|
|
||||||
- [ ] Stonecutter
|
|
||||||
- [ ] Structure Block
|
|
||||||
- [ ] Horse Inventory
|
|
||||||
- [ ] Loom
|
|
||||||
- [ ] Smithing Table
|
|
||||||
- Some Entity Flags
|
- Some Entity Flags
|
||||||
|
- The Following Inventories
|
||||||
|
- Enchantment Table (as a proper GUI)
|
||||||
|
- Beacon
|
||||||
|
- Cartography Table
|
||||||
|
- Stonecutter
|
||||||
|
- Structure Block
|
||||||
|
- Horse Inventory
|
||||||
|
- Loom
|
||||||
|
- Smithing Table
|
||||||
|
|
||||||
|
## What can't be fixed
|
||||||
|
The following things can't be fixed because of Bedrock limitations. They might be fixable in the future, but not as of now.
|
||||||
|
|
||||||
|
- Custom heads in inventories
|
||||||
|
- Clickable links in chat
|
||||||
|
- Glowing effect
|
||||||
|
|
||||||
## Compiling
|
## Compiling
|
||||||
1. Clone the repo to your computer
|
1. Clone the repo to your computer
|
||||||
|
|
|
@ -6,15 +6,15 @@
|
||||||
<parent>
|
<parent>
|
||||||
<groupId>org.geysermc</groupId>
|
<groupId>org.geysermc</groupId>
|
||||||
<artifactId>bootstrap-parent</artifactId>
|
<artifactId>bootstrap-parent</artifactId>
|
||||||
<version>1.1.0</version>
|
<version>1.2.0-SNAPSHOT</version>
|
||||||
<relativePath>../</relativePath>
|
|
||||||
</parent>
|
</parent>
|
||||||
<artifactId>bootstrap-bungeecord</artifactId>
|
<artifactId>bootstrap-bungeecord</artifactId>
|
||||||
|
|
||||||
<dependencies>
|
<dependencies>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.geysermc</groupId>
|
<groupId>org.geysermc</groupId>
|
||||||
<artifactId>connector</artifactId>
|
<artifactId>connector</artifactId>
|
||||||
<version>1.1.0</version>
|
<version>1.2.0-SNAPSHOT</version>
|
||||||
<scope>compile</scope>
|
<scope>compile</scope>
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
|
|
|
@ -47,14 +47,12 @@ import java.util.concurrent.CompletableFuture;
|
||||||
@AllArgsConstructor
|
@AllArgsConstructor
|
||||||
public class GeyserBungeePingPassthrough implements IGeyserPingPassthrough, Listener {
|
public class GeyserBungeePingPassthrough implements IGeyserPingPassthrough, Listener {
|
||||||
|
|
||||||
private static final GeyserPendingConnection PENDING_CONNECTION = new GeyserPendingConnection();
|
|
||||||
|
|
||||||
private final ProxyServer proxyServer;
|
private final ProxyServer proxyServer;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public GeyserPingInfo getPingInformation() {
|
public GeyserPingInfo getPingInformation(InetSocketAddress inetSocketAddress) {
|
||||||
CompletableFuture<ProxyPingEvent> future = new CompletableFuture<>();
|
CompletableFuture<ProxyPingEvent> future = new CompletableFuture<>();
|
||||||
proxyServer.getPluginManager().callEvent(new ProxyPingEvent(PENDING_CONNECTION, getPingInfo(), (event, throwable) -> {
|
proxyServer.getPluginManager().callEvent(new ProxyPingEvent(new GeyserPendingConnection(inetSocketAddress), getPingInfo(), (event, throwable) -> {
|
||||||
if (throwable != null) future.completeExceptionally(throwable);
|
if (throwable != null) future.completeExceptionally(throwable);
|
||||||
else future.complete(event);
|
else future.complete(event);
|
||||||
}));
|
}));
|
||||||
|
@ -89,7 +87,12 @@ public class GeyserBungeePingPassthrough implements IGeyserPingPassthrough, List
|
||||||
private static class GeyserPendingConnection implements PendingConnection {
|
private static class GeyserPendingConnection implements PendingConnection {
|
||||||
|
|
||||||
private static final UUID FAKE_UUID = UUID.nameUUIDFromBytes("geyser!internal".getBytes());
|
private static final UUID FAKE_UUID = UUID.nameUUIDFromBytes("geyser!internal".getBytes());
|
||||||
private static final InetSocketAddress FAKE_REMOTE = new InetSocketAddress(Inet4Address.getLoopbackAddress(), 69);
|
|
||||||
|
private final InetSocketAddress remote;
|
||||||
|
|
||||||
|
public GeyserPendingConnection(InetSocketAddress remote) {
|
||||||
|
this.remote = remote;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String getName() {
|
public String getName() {
|
||||||
|
@ -143,7 +146,7 @@ public class GeyserBungeePingPassthrough implements IGeyserPingPassthrough, List
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public InetSocketAddress getAddress() {
|
public InetSocketAddress getAddress() {
|
||||||
return FAKE_REMOTE;
|
return remote;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -27,10 +27,10 @@ package org.geysermc.platform.bungeecord;
|
||||||
|
|
||||||
import net.md_5.bungee.api.config.ListenerInfo;
|
import net.md_5.bungee.api.config.ListenerInfo;
|
||||||
import net.md_5.bungee.api.plugin.Plugin;
|
import net.md_5.bungee.api.plugin.Plugin;
|
||||||
|
import org.geysermc.common.PlatformType;
|
||||||
import org.geysermc.connector.GeyserConnector;
|
import org.geysermc.connector.GeyserConnector;
|
||||||
import org.geysermc.connector.bootstrap.GeyserBootstrap;
|
import org.geysermc.connector.bootstrap.GeyserBootstrap;
|
||||||
import org.geysermc.connector.command.CommandManager;
|
import org.geysermc.connector.command.CommandManager;
|
||||||
import org.geysermc.connector.common.PlatformType;
|
|
||||||
import org.geysermc.connector.configuration.GeyserConfiguration;
|
import org.geysermc.connector.configuration.GeyserConfiguration;
|
||||||
import org.geysermc.connector.dump.BootstrapDumpInfo;
|
import org.geysermc.connector.dump.BootstrapDumpInfo;
|
||||||
import org.geysermc.connector.ping.GeyserLegacyPingPassthrough;
|
import org.geysermc.connector.ping.GeyserLegacyPingPassthrough;
|
||||||
|
|
|
@ -25,17 +25,20 @@
|
||||||
|
|
||||||
package org.geysermc.platform.bungeecord.command;
|
package org.geysermc.platform.bungeecord.command;
|
||||||
|
|
||||||
import lombok.AllArgsConstructor;
|
|
||||||
|
|
||||||
import net.md_5.bungee.api.chat.TextComponent;
|
import net.md_5.bungee.api.chat.TextComponent;
|
||||||
import net.md_5.bungee.api.connection.ProxiedPlayer;
|
import net.md_5.bungee.api.connection.ProxiedPlayer;
|
||||||
|
|
||||||
import org.geysermc.connector.command.CommandSender;
|
import org.geysermc.connector.command.CommandSender;
|
||||||
|
import org.geysermc.connector.utils.LanguageUtils;
|
||||||
|
|
||||||
@AllArgsConstructor
|
|
||||||
public class BungeeCommandSender implements CommandSender {
|
public class BungeeCommandSender implements CommandSender {
|
||||||
|
|
||||||
private net.md_5.bungee.api.CommandSender handle;
|
private final net.md_5.bungee.api.CommandSender handle;
|
||||||
|
|
||||||
|
public BungeeCommandSender(net.md_5.bungee.api.CommandSender handle) {
|
||||||
|
this.handle = handle;
|
||||||
|
// Ensure even Java players' languages are loaded
|
||||||
|
LanguageUtils.loadGeyserLocale(getLocale());
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String getName() {
|
public String getName() {
|
||||||
|
@ -51,4 +54,14 @@ public class BungeeCommandSender implements CommandSender {
|
||||||
public boolean isConsole() {
|
public boolean isConsole() {
|
||||||
return !(handle instanceof ProxiedPlayer);
|
return !(handle instanceof ProxiedPlayer);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getLocale() {
|
||||||
|
if (handle instanceof ProxiedPlayer) {
|
||||||
|
ProxiedPlayer player = (ProxiedPlayer) handle;
|
||||||
|
String locale = player.getLocale().getLanguage() + "_" + player.getLocale().getCountry();
|
||||||
|
return LanguageUtils.formatLocale(locale);
|
||||||
|
}
|
||||||
|
return LanguageUtils.getDefaultLocale();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -27,13 +27,10 @@ package org.geysermc.platform.bungeecord.command;
|
||||||
|
|
||||||
import net.md_5.bungee.api.ChatColor;
|
import net.md_5.bungee.api.ChatColor;
|
||||||
import net.md_5.bungee.api.CommandSender;
|
import net.md_5.bungee.api.CommandSender;
|
||||||
import net.md_5.bungee.api.chat.TextComponent;
|
|
||||||
import net.md_5.bungee.api.plugin.Command;
|
import net.md_5.bungee.api.plugin.Command;
|
||||||
import net.md_5.bungee.api.plugin.TabExecutor;
|
import net.md_5.bungee.api.plugin.TabExecutor;
|
||||||
|
|
||||||
import org.geysermc.connector.GeyserConnector;
|
import org.geysermc.connector.GeyserConnector;
|
||||||
import org.geysermc.connector.command.GeyserCommand;
|
import org.geysermc.connector.command.GeyserCommand;
|
||||||
import org.geysermc.connector.network.session.GeyserSession;
|
|
||||||
import org.geysermc.connector.utils.LanguageUtils;
|
import org.geysermc.connector.utils.LanguageUtils;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
@ -41,7 +38,7 @@ import java.util.Arrays;
|
||||||
|
|
||||||
public class GeyserBungeeCommandExecutor extends Command implements TabExecutor {
|
public class GeyserBungeeCommandExecutor extends Command implements TabExecutor {
|
||||||
|
|
||||||
private GeyserConnector connector;
|
private final GeyserConnector connector;
|
||||||
|
|
||||||
public GeyserBungeeCommandExecutor(GeyserConnector connector) {
|
public GeyserBungeeCommandExecutor(GeyserConnector connector) {
|
||||||
super("geyser");
|
super("geyser");
|
||||||
|
@ -54,14 +51,10 @@ public class GeyserBungeeCommandExecutor extends Command implements TabExecutor
|
||||||
if (args.length > 0) {
|
if (args.length > 0) {
|
||||||
if (getCommand(args[0]) != null) {
|
if (getCommand(args[0]) != null) {
|
||||||
if (!sender.hasPermission(getCommand(args[0]).getPermission())) {
|
if (!sender.hasPermission(getCommand(args[0]).getPermission())) {
|
||||||
String message = "";
|
BungeeCommandSender commandSender = new BungeeCommandSender(sender);
|
||||||
if (sender instanceof GeyserSession) {
|
String message = LanguageUtils.getPlayerLocaleString("geyser.bootstrap.command.permission_fail", commandSender.getLocale());
|
||||||
message = LanguageUtils.getPlayerLocaleString("geyser.bootstrap.command.permission_fail", ((GeyserSession) sender).getClientData().getLanguageCode());
|
|
||||||
} else {
|
|
||||||
message = LanguageUtils.getLocaleStringLog("geyser.bootstrap.command.permission_fail");
|
|
||||||
}
|
|
||||||
|
|
||||||
sender.sendMessage(TextComponent.fromLegacyText(ChatColor.RED + message));
|
commandSender.sendMessage(ChatColor.RED + message);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
getCommand(args[0]).execute(new BungeeCommandSender(sender), args.length > 1 ? Arrays.copyOfRange(args, 1, args.length) : new String[0]);
|
getCommand(args[0]).execute(new BungeeCommandSender(sender), args.length > 1 ? Arrays.copyOfRange(args, 1, args.length) : new String[0]);
|
||||||
|
@ -74,7 +67,7 @@ public class GeyserBungeeCommandExecutor extends Command implements TabExecutor
|
||||||
@Override
|
@Override
|
||||||
public Iterable<String> onTabComplete(CommandSender sender, String[] args) {
|
public Iterable<String> onTabComplete(CommandSender sender, String[] args) {
|
||||||
if (args.length == 1) {
|
if (args.length == 1) {
|
||||||
return Arrays.asList("?", "help", "reload", "shutdown", "stop");
|
return connector.getCommandManager().getCommandNames();
|
||||||
}
|
}
|
||||||
return new ArrayList<>();
|
return new ArrayList<>();
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,12 +6,11 @@
|
||||||
<parent>
|
<parent>
|
||||||
<groupId>org.geysermc</groupId>
|
<groupId>org.geysermc</groupId>
|
||||||
<artifactId>geyser-parent</artifactId>
|
<artifactId>geyser-parent</artifactId>
|
||||||
<version>parent</version>
|
<version>1.2.0-SNAPSHOT</version>
|
||||||
<relativePath>../</relativePath>
|
|
||||||
</parent>
|
</parent>
|
||||||
<artifactId>bootstrap-parent</artifactId>
|
<artifactId>bootstrap-parent</artifactId>
|
||||||
<version>1.1.0</version>
|
|
||||||
<packaging>pom</packaging>
|
<packaging>pom</packaging>
|
||||||
|
|
||||||
<repositories>
|
<repositories>
|
||||||
<repository>
|
<repository>
|
||||||
<id>spigot-public</id>
|
<id>spigot-public</id>
|
||||||
|
|
|
@ -6,15 +6,15 @@
|
||||||
<parent>
|
<parent>
|
||||||
<groupId>org.geysermc</groupId>
|
<groupId>org.geysermc</groupId>
|
||||||
<artifactId>bootstrap-parent</artifactId>
|
<artifactId>bootstrap-parent</artifactId>
|
||||||
<version>1.1.0</version>
|
<version>1.2.0-SNAPSHOT</version>
|
||||||
<relativePath>../</relativePath>
|
|
||||||
</parent>
|
</parent>
|
||||||
<artifactId>bootstrap-spigot</artifactId>
|
<artifactId>bootstrap-spigot</artifactId>
|
||||||
|
|
||||||
<dependencies>
|
<dependencies>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.geysermc</groupId>
|
<groupId>org.geysermc</groupId>
|
||||||
<artifactId>connector</artifactId>
|
<artifactId>connector</artifactId>
|
||||||
<version>1.1.0</version>
|
<version>1.2.0-SNAPSHOT</version>
|
||||||
<scope>compile</scope>
|
<scope>compile</scope>
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
|
@ -26,9 +26,14 @@
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>us.myles</groupId>
|
<groupId>us.myles</groupId>
|
||||||
<artifactId>viaversion</artifactId>
|
<artifactId>viaversion</artifactId>
|
||||||
<version>3.1.1</version>
|
<version>3.2.0</version>
|
||||||
<scope>provided</scope>
|
<scope>provided</scope>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.geysermc.adapters</groupId>
|
||||||
|
<artifactId>spigot-all</artifactId>
|
||||||
|
<version>1.0-SNAPSHOT</version>
|
||||||
|
</dependency>
|
||||||
</dependencies>
|
</dependencies>
|
||||||
<build>
|
<build>
|
||||||
<finalName>${outputName}-Spigot</finalName>
|
<finalName>${outputName}-Spigot</finalName>
|
||||||
|
|
|
@ -35,6 +35,7 @@ import org.geysermc.connector.common.ping.GeyserPingInfo;
|
||||||
import org.geysermc.connector.ping.IGeyserPingPassthrough;
|
import org.geysermc.connector.ping.IGeyserPingPassthrough;
|
||||||
|
|
||||||
import java.net.InetAddress;
|
import java.net.InetAddress;
|
||||||
|
import java.net.InetSocketAddress;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.Iterator;
|
import java.util.Iterator;
|
||||||
|
|
||||||
|
@ -44,9 +45,9 @@ public class GeyserSpigotPingPassthrough implements IGeyserPingPassthrough {
|
||||||
private final GeyserSpigotLogger logger;
|
private final GeyserSpigotLogger logger;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public GeyserPingInfo getPingInformation() {
|
public GeyserPingInfo getPingInformation(InetSocketAddress inetSocketAddress) {
|
||||||
try {
|
try {
|
||||||
ServerListPingEvent event = new GeyserPingEvent(InetAddress.getLocalHost(), Bukkit.getMotd(), Bukkit.getOnlinePlayers().size(), Bukkit.getMaxPlayers());
|
ServerListPingEvent event = new GeyserPingEvent(inetSocketAddress.getAddress(), Bukkit.getMotd(), Bukkit.getOnlinePlayers().size(), Bukkit.getMaxPlayers());
|
||||||
Bukkit.getPluginManager().callEvent(event);
|
Bukkit.getPluginManager().callEvent(event);
|
||||||
GeyserPingInfo geyserPingInfo = new GeyserPingInfo(event.getMotd(),
|
GeyserPingInfo geyserPingInfo = new GeyserPingInfo(event.getMotd(),
|
||||||
new GeyserPingInfo.Players(event.getMaxPlayers(), event.getNumPlayers()),
|
new GeyserPingInfo.Players(event.getMaxPlayers(), event.getNumPlayers()),
|
||||||
|
|
|
@ -25,12 +25,14 @@
|
||||||
|
|
||||||
package org.geysermc.platform.spigot;
|
package org.geysermc.platform.spigot;
|
||||||
|
|
||||||
|
import com.github.steveice10.mc.protocol.MinecraftConstants;
|
||||||
import org.bukkit.Bukkit;
|
import org.bukkit.Bukkit;
|
||||||
import org.bukkit.plugin.java.JavaPlugin;
|
import org.bukkit.plugin.java.JavaPlugin;
|
||||||
|
import org.geysermc.adapters.spigot.SpigotAdapters;
|
||||||
|
import org.geysermc.common.PlatformType;
|
||||||
import org.geysermc.connector.GeyserConnector;
|
import org.geysermc.connector.GeyserConnector;
|
||||||
import org.geysermc.connector.bootstrap.GeyserBootstrap;
|
import org.geysermc.connector.bootstrap.GeyserBootstrap;
|
||||||
import org.geysermc.connector.command.CommandManager;
|
import org.geysermc.connector.command.CommandManager;
|
||||||
import org.geysermc.connector.common.PlatformType;
|
|
||||||
import org.geysermc.connector.configuration.GeyserConfiguration;
|
import org.geysermc.connector.configuration.GeyserConfiguration;
|
||||||
import org.geysermc.connector.dump.BootstrapDumpInfo;
|
import org.geysermc.connector.dump.BootstrapDumpInfo;
|
||||||
import org.geysermc.connector.network.translators.world.WorldManager;
|
import org.geysermc.connector.network.translators.world.WorldManager;
|
||||||
|
@ -40,18 +42,25 @@ import org.geysermc.connector.utils.FileUtils;
|
||||||
import org.geysermc.connector.utils.LanguageUtils;
|
import org.geysermc.connector.utils.LanguageUtils;
|
||||||
import org.geysermc.platform.spigot.command.GeyserSpigotCommandExecutor;
|
import org.geysermc.platform.spigot.command.GeyserSpigotCommandExecutor;
|
||||||
import org.geysermc.platform.spigot.command.GeyserSpigotCommandManager;
|
import org.geysermc.platform.spigot.command.GeyserSpigotCommandManager;
|
||||||
|
import org.geysermc.platform.spigot.command.SpigotCommandSender;
|
||||||
import org.geysermc.platform.spigot.world.GeyserSpigotBlockPlaceListener;
|
import org.geysermc.platform.spigot.world.GeyserSpigotBlockPlaceListener;
|
||||||
import org.geysermc.platform.spigot.world.GeyserSpigotWorldManager;
|
import org.geysermc.platform.spigot.world.manager.*;
|
||||||
|
import us.myles.ViaVersion.api.Pair;
|
||||||
|
import us.myles.ViaVersion.api.Via;
|
||||||
|
import us.myles.ViaVersion.api.data.MappingData;
|
||||||
|
import us.myles.ViaVersion.api.protocol.Protocol;
|
||||||
|
import us.myles.ViaVersion.api.protocol.ProtocolRegistry;
|
||||||
|
import us.myles.ViaVersion.api.protocol.ProtocolVersion;
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.nio.file.Files;
|
import java.nio.file.Files;
|
||||||
import java.nio.file.Path;
|
import java.nio.file.Path;
|
||||||
|
import java.util.List;
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
import java.util.logging.Level;
|
import java.util.logging.Level;
|
||||||
|
|
||||||
public class GeyserSpigotPlugin extends JavaPlugin implements GeyserBootstrap {
|
public class GeyserSpigotPlugin extends JavaPlugin implements GeyserBootstrap {
|
||||||
|
|
||||||
private GeyserSpigotCommandManager geyserCommandManager;
|
private GeyserSpigotCommandManager geyserCommandManager;
|
||||||
private GeyserSpigotConfiguration geyserConfig;
|
private GeyserSpigotConfiguration geyserConfig;
|
||||||
private GeyserSpigotLogger geyserLogger;
|
private GeyserSpigotLogger geyserLogger;
|
||||||
|
@ -120,6 +129,13 @@ public class GeyserSpigotPlugin extends JavaPlugin implements GeyserBootstrap {
|
||||||
this.geyserCommandManager = new GeyserSpigotCommandManager(this, connector);
|
this.geyserCommandManager = new GeyserSpigotCommandManager(this, connector);
|
||||||
|
|
||||||
boolean isViaVersion = (Bukkit.getPluginManager().getPlugin("ViaVersion") != null);
|
boolean isViaVersion = (Bukkit.getPluginManager().getPlugin("ViaVersion") != null);
|
||||||
|
if (isViaVersion) {
|
||||||
|
if (!isCompatible(Via.getAPI().getVersion().replace("-SNAPSHOT", ""), "3.2.0")) {
|
||||||
|
geyserLogger.warning(LanguageUtils.getLocaleStringLog("geyser.bootstrap.viaversion.too_old",
|
||||||
|
"https://ci.viaversion.com/job/ViaVersion/"));
|
||||||
|
isViaVersion = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
// Used to determine if Block.getBlockData() is present.
|
// Used to determine if Block.getBlockData() is present.
|
||||||
boolean isLegacy = !isCompatible(Bukkit.getServer().getVersion(), "1.13.0");
|
boolean isLegacy = !isCompatible(Bukkit.getServer().getVersion(), "1.13.0");
|
||||||
if (isLegacy)
|
if (isLegacy)
|
||||||
|
@ -130,8 +146,51 @@ public class GeyserSpigotPlugin extends JavaPlugin implements GeyserBootstrap {
|
||||||
geyserLogger.debug("Legacy version of Minecraft (1.15.2 or older) detected; not using 3D biomes.");
|
geyserLogger.debug("Legacy version of Minecraft (1.15.2 or older) detected; not using 3D biomes.");
|
||||||
}
|
}
|
||||||
|
|
||||||
this.geyserWorldManager = new GeyserSpigotWorldManager(isLegacy, use3dBiomes, isViaVersion);
|
// Set if we need to use a different method for getting a player's locale
|
||||||
GeyserSpigotBlockPlaceListener blockPlaceListener = new GeyserSpigotBlockPlaceListener(connector, isLegacy, isViaVersion);
|
SpigotCommandSender.setUseLegacyLocaleMethod(!isCompatible(Bukkit.getServer().getVersion(), "1.12.0"));
|
||||||
|
|
||||||
|
if (connector.getConfig().isUseAdapters()) {
|
||||||
|
try {
|
||||||
|
String name = Bukkit.getServer().getClass().getPackage().getName();
|
||||||
|
String nmsVersion = name.substring(name.lastIndexOf('.') + 1);
|
||||||
|
SpigotAdapters.registerWorldAdapter(nmsVersion);
|
||||||
|
if (isViaVersion && isViaVersionNeeded()) {
|
||||||
|
if (isLegacy) {
|
||||||
|
// Pre-1.13
|
||||||
|
this.geyserWorldManager = new GeyserSpigot1_12NativeWorldManager();
|
||||||
|
} else {
|
||||||
|
// Post-1.13
|
||||||
|
this.geyserWorldManager = new GeyserSpigotLegacyNativeWorldManager(this, use3dBiomes);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// No ViaVersion
|
||||||
|
this.geyserWorldManager = new GeyserSpigotNativeWorldManager(use3dBiomes);
|
||||||
|
}
|
||||||
|
geyserLogger.debug("Using NMS adapter: " + this.geyserWorldManager.getClass() + ", " + nmsVersion);
|
||||||
|
} catch (Exception e) {
|
||||||
|
if (geyserConfig.isDebugMode()) {
|
||||||
|
geyserLogger.debug("Error while attempting to find NMS adapter. Most likely, this can be safely ignored. :)");
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
geyserLogger.debug("Not using NMS adapter as it is disabled in the config.");
|
||||||
|
}
|
||||||
|
if (this.geyserWorldManager == null) {
|
||||||
|
// No NMS adapter
|
||||||
|
if (isLegacy && isViaVersion) {
|
||||||
|
// Use ViaVersion for converting pre-1.13 block states
|
||||||
|
this.geyserWorldManager = new GeyserSpigot1_12WorldManager();
|
||||||
|
} else if (isLegacy) {
|
||||||
|
// Not sure how this happens - without ViaVersion, we don't know any block states, so just assume everything is air
|
||||||
|
this.geyserWorldManager = new GeyserSpigotFallbackWorldManager();
|
||||||
|
} else {
|
||||||
|
// Post-1.13
|
||||||
|
this.geyserWorldManager = new GeyserSpigotWorldManager(use3dBiomes);
|
||||||
|
}
|
||||||
|
geyserLogger.debug("Using default world manager: " + this.geyserWorldManager.getClass());
|
||||||
|
}
|
||||||
|
GeyserSpigotBlockPlaceListener blockPlaceListener = new GeyserSpigotBlockPlaceListener(connector, this.geyserWorldManager);
|
||||||
|
|
||||||
Bukkit.getServer().getPluginManager().registerEvents(blockPlaceListener, this);
|
Bukkit.getServer().getPluginManager().registerEvents(blockPlaceListener, this);
|
||||||
|
|
||||||
|
@ -140,9 +199,10 @@ public class GeyserSpigotPlugin extends JavaPlugin implements GeyserBootstrap {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onDisable() {
|
public void onDisable() {
|
||||||
if (connector != null)
|
if (connector != null) {
|
||||||
connector.shutdown();
|
connector.shutdown();
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public GeyserSpigotConfiguration getGeyserConfig() {
|
public GeyserSpigotConfiguration getGeyserConfig() {
|
||||||
|
@ -174,6 +234,11 @@ public class GeyserSpigotPlugin extends JavaPlugin implements GeyserBootstrap {
|
||||||
return getDataFolder().toPath();
|
return getDataFolder().toPath();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public BootstrapDumpInfo getDumpInfo() {
|
||||||
|
return new GeyserSpigotDumpInfo();
|
||||||
|
}
|
||||||
|
|
||||||
public boolean isCompatible(String version, String whichVersion) {
|
public boolean isCompatible(String version, String whichVersion) {
|
||||||
int[] currentVersion = parseVersion(version);
|
int[] currentVersion = parseVersion(version);
|
||||||
int[] otherVersion = parseVersion(whichVersion);
|
int[] otherVersion = parseVersion(whichVersion);
|
||||||
|
@ -208,8 +273,36 @@ public class GeyserSpigotPlugin extends JavaPlugin implements GeyserBootstrap {
|
||||||
return temp;
|
return temp;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
/**
|
||||||
public BootstrapDumpInfo getDumpInfo() {
|
* @return the server version before ViaVersion finishes initializing
|
||||||
return new GeyserSpigotDumpInfo();
|
*/
|
||||||
|
public ProtocolVersion getServerProtocolVersion() {
|
||||||
|
String bukkitVersion = Bukkit.getServer().getVersion();
|
||||||
|
// Turn "(MC: 1.16.4)" into 1.16.4.
|
||||||
|
String version = bukkitVersion.split("\\(MC: ")[1].split("\\)")[0];
|
||||||
|
return ProtocolVersion.getClosest(version);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This function should not run unless ViaVersion is installed on the server.
|
||||||
|
*
|
||||||
|
* @return true if there is any block mappings difference between the server and client.
|
||||||
|
*/
|
||||||
|
private boolean isViaVersionNeeded() {
|
||||||
|
ProtocolVersion serverVersion = getServerProtocolVersion();
|
||||||
|
List<Pair<Integer, Protocol>> protocolList = ProtocolRegistry.getProtocolPath(MinecraftConstants.PROTOCOL_VERSION,
|
||||||
|
serverVersion.getVersion());
|
||||||
|
if (protocolList == null) {
|
||||||
|
// No translation needed!
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
for (int i = protocolList.size() - 1; i >= 0; i--) {
|
||||||
|
MappingData mappingData = protocolList.get(i).getValue().getMappingData();
|
||||||
|
if (mappingData != null) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// All mapping data is null, which means client and server block states are the same
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -32,7 +32,6 @@ import org.bukkit.command.CommandSender;
|
||||||
import org.bukkit.command.TabExecutor;
|
import org.bukkit.command.TabExecutor;
|
||||||
import org.geysermc.connector.GeyserConnector;
|
import org.geysermc.connector.GeyserConnector;
|
||||||
import org.geysermc.connector.command.GeyserCommand;
|
import org.geysermc.connector.command.GeyserCommand;
|
||||||
import org.geysermc.connector.network.session.GeyserSession;
|
|
||||||
import org.geysermc.connector.utils.LanguageUtils;
|
import org.geysermc.connector.utils.LanguageUtils;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
@ -42,21 +41,17 @@ import java.util.List;
|
||||||
@AllArgsConstructor
|
@AllArgsConstructor
|
||||||
public class GeyserSpigotCommandExecutor implements TabExecutor {
|
public class GeyserSpigotCommandExecutor implements TabExecutor {
|
||||||
|
|
||||||
private GeyserConnector connector;
|
private final GeyserConnector connector;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean onCommand(CommandSender sender, Command command, String label, String[] args) {
|
public boolean onCommand(CommandSender sender, Command command, String label, String[] args) {
|
||||||
if (args.length > 0) {
|
if (args.length > 0) {
|
||||||
if (getCommand(args[0]) != null) {
|
if (getCommand(args[0]) != null) {
|
||||||
if (!sender.hasPermission(getCommand(args[0]).getPermission())) {
|
if (!sender.hasPermission(getCommand(args[0]).getPermission())) {
|
||||||
String message = "";
|
SpigotCommandSender commandSender = new SpigotCommandSender(sender);
|
||||||
if (sender instanceof GeyserSession) {
|
String message = LanguageUtils.getPlayerLocaleString("geyser.bootstrap.command.permission_fail", commandSender.getLocale());;
|
||||||
message = LanguageUtils.getPlayerLocaleString("geyser.bootstrap.command.permission_fail", ((GeyserSession) sender).getClientData().getLanguageCode());
|
|
||||||
} else {
|
|
||||||
message = LanguageUtils.getLocaleStringLog("geyser.bootstrap.command.permission_fail");
|
|
||||||
}
|
|
||||||
|
|
||||||
sender.sendMessage(ChatColor.RED + message);
|
commandSender.sendMessage(ChatColor.RED + message);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
getCommand(args[0]).execute(new SpigotCommandSender(sender), args.length > 1 ? Arrays.copyOfRange(args, 1, args.length) : new String[0]);
|
getCommand(args[0]).execute(new SpigotCommandSender(sender), args.length > 1 ? Arrays.copyOfRange(args, 1, args.length) : new String[0]);
|
||||||
|
@ -72,7 +67,7 @@ public class GeyserSpigotCommandExecutor implements TabExecutor {
|
||||||
@Override
|
@Override
|
||||||
public List<String> onTabComplete(CommandSender sender, Command command, String label, String[] args) {
|
public List<String> onTabComplete(CommandSender sender, Command command, String label, String[] args) {
|
||||||
if (args.length == 1) {
|
if (args.length == 1) {
|
||||||
return Arrays.asList("?", "help", "reload", "shutdown", "stop");
|
return connector.getCommandManager().getCommandNames();
|
||||||
}
|
}
|
||||||
return new ArrayList<>();
|
return new ArrayList<>();
|
||||||
}
|
}
|
||||||
|
|
|
@ -25,15 +25,33 @@
|
||||||
|
|
||||||
package org.geysermc.platform.spigot.command;
|
package org.geysermc.platform.spigot.command;
|
||||||
|
|
||||||
import lombok.AllArgsConstructor;
|
|
||||||
|
|
||||||
import org.bukkit.command.ConsoleCommandSender;
|
import org.bukkit.command.ConsoleCommandSender;
|
||||||
|
import org.bukkit.entity.Player;
|
||||||
|
import org.geysermc.connector.GeyserConnector;
|
||||||
import org.geysermc.connector.command.CommandSender;
|
import org.geysermc.connector.command.CommandSender;
|
||||||
|
import org.geysermc.connector.utils.LanguageUtils;
|
||||||
|
|
||||||
|
import java.lang.reflect.InvocationTargetException;
|
||||||
|
import java.lang.reflect.Method;
|
||||||
|
|
||||||
@AllArgsConstructor
|
|
||||||
public class SpigotCommandSender implements CommandSender {
|
public class SpigotCommandSender implements CommandSender {
|
||||||
|
|
||||||
private org.bukkit.command.CommandSender handle;
|
/**
|
||||||
|
* Whether to use {@code Player.getLocale()} or {@code Player.spigot().getLocale()}, depending on version.
|
||||||
|
* 1.12 or greater should not use the legacy method.
|
||||||
|
*/
|
||||||
|
private static boolean USE_LEGACY_METHOD = false;
|
||||||
|
private static Method LOCALE_METHOD;
|
||||||
|
|
||||||
|
private final org.bukkit.command.CommandSender handle;
|
||||||
|
private final String locale;
|
||||||
|
|
||||||
|
public SpigotCommandSender(org.bukkit.command.CommandSender handle) {
|
||||||
|
this.handle = handle;
|
||||||
|
this.locale = getSpigotLocale();
|
||||||
|
// Ensure even Java players' languages are loaded
|
||||||
|
LanguageUtils.loadGeyserLocale(locale);
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String getName() {
|
public String getName() {
|
||||||
|
@ -49,4 +67,49 @@ public class SpigotCommandSender implements CommandSender {
|
||||||
public boolean isConsole() {
|
public boolean isConsole() {
|
||||||
return handle instanceof ConsoleCommandSender;
|
return handle instanceof ConsoleCommandSender;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getLocale() {
|
||||||
|
return locale;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set if we are on pre-1.12, and therefore {@code player.getLocale()} doesn't exist and we have to get
|
||||||
|
* {@code player.spigot().getLocale()}.
|
||||||
|
*
|
||||||
|
* @param useLegacyMethod if we are running pre-1.12 and therefore need to use reflection to get the player locale
|
||||||
|
*/
|
||||||
|
public static void setUseLegacyLocaleMethod(boolean useLegacyMethod) {
|
||||||
|
USE_LEGACY_METHOD = useLegacyMethod;
|
||||||
|
if (USE_LEGACY_METHOD) {
|
||||||
|
try {
|
||||||
|
//noinspection JavaReflectionMemberAccess - of course it doesn't exist; that's why we're doing it
|
||||||
|
LOCALE_METHOD = Player.Spigot.class.getMethod("getLocale");
|
||||||
|
} catch (NoSuchMethodException e) {
|
||||||
|
GeyserConnector.getInstance().getLogger().debug("Player.Spigot.getLocale() doesn't exist? Not a big deal but if you're seeing this please report it to the developers!");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* So we only have to do nasty reflection stuff once per command
|
||||||
|
*
|
||||||
|
* @return the locale of the Spigot player
|
||||||
|
*/
|
||||||
|
private String getSpigotLocale() {
|
||||||
|
if (handle instanceof Player) {
|
||||||
|
Player player = (Player) handle;
|
||||||
|
if (USE_LEGACY_METHOD) {
|
||||||
|
try {
|
||||||
|
// sigh
|
||||||
|
// This was the only option on older Spigot instances and now it's gone
|
||||||
|
return (String) LOCALE_METHOD.invoke(player.spigot());
|
||||||
|
} catch (IllegalAccessException | InvocationTargetException ignored) {
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return player.getLocale();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return LanguageUtils.getDefaultLocale();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -36,13 +36,13 @@ import org.bukkit.event.block.BlockPlaceEvent;
|
||||||
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.world.block.BlockTranslator;
|
import org.geysermc.connector.network.translators.world.block.BlockTranslator;
|
||||||
|
import org.geysermc.platform.spigot.world.manager.GeyserSpigotWorldManager;
|
||||||
|
|
||||||
@AllArgsConstructor
|
@AllArgsConstructor
|
||||||
public class GeyserSpigotBlockPlaceListener implements Listener {
|
public class GeyserSpigotBlockPlaceListener implements Listener {
|
||||||
|
|
||||||
private final GeyserConnector connector;
|
private final GeyserConnector connector;
|
||||||
private final boolean isLegacy;
|
private final GeyserSpigotWorldManager worldManager;
|
||||||
private final boolean isViaVersion;
|
|
||||||
|
|
||||||
@EventHandler
|
@EventHandler
|
||||||
public void place(final BlockPlaceEvent event) {
|
public void place(final BlockPlaceEvent event) {
|
||||||
|
@ -52,14 +52,13 @@ public class GeyserSpigotBlockPlaceListener implements Listener {
|
||||||
placeBlockSoundPacket.setSound(SoundEvent.PLACE);
|
placeBlockSoundPacket.setSound(SoundEvent.PLACE);
|
||||||
placeBlockSoundPacket.setPosition(Vector3f.from(event.getBlockPlaced().getX(), event.getBlockPlaced().getY(), event.getBlockPlaced().getZ()));
|
placeBlockSoundPacket.setPosition(Vector3f.from(event.getBlockPlaced().getX(), event.getBlockPlaced().getY(), event.getBlockPlaced().getZ()));
|
||||||
placeBlockSoundPacket.setBabySound(false);
|
placeBlockSoundPacket.setBabySound(false);
|
||||||
String javaBlockId;
|
if (worldManager.isLegacy()) {
|
||||||
if (isLegacy) {
|
placeBlockSoundPacket.setExtraData(BlockTranslator.getBedrockBlockId(worldManager.getBlockAt(session,
|
||||||
javaBlockId = BlockTranslator.getJavaIdBlockMap().inverse().get(GeyserSpigotWorldManager.getLegacyBlock(session,
|
event.getBlockPlaced().getX(), event.getBlockPlaced().getY(), event.getBlockPlaced().getZ())));
|
||||||
event.getBlockPlaced().getX(), event.getBlockPlaced().getY(), event.getBlockPlaced().getZ(), isViaVersion));
|
|
||||||
} else {
|
} else {
|
||||||
javaBlockId = event.getBlockPlaced().getBlockData().getAsString();
|
String javaBlockId = event.getBlockPlaced().getBlockData().getAsString();
|
||||||
|
placeBlockSoundPacket.setExtraData(BlockTranslator.getBedrockBlockId(BlockTranslator.getJavaIdBlockMap().getOrDefault(javaBlockId, BlockTranslator.JAVA_AIR_ID)));
|
||||||
}
|
}
|
||||||
placeBlockSoundPacket.setExtraData(BlockTranslator.getBedrockBlockId(BlockTranslator.getJavaIdBlockMap().getOrDefault(javaBlockId, 0)));
|
|
||||||
placeBlockSoundPacket.setIdentifier(":");
|
placeBlockSoundPacket.setIdentifier(":");
|
||||||
session.sendUpstreamPacket(placeBlockSoundPacket);
|
session.sendUpstreamPacket(placeBlockSoundPacket);
|
||||||
session.setLastBlockPlacePosition(null);
|
session.setLastBlockPlacePosition(null);
|
||||||
|
|
|
@ -0,0 +1,59 @@
|
||||||
|
/*
|
||||||
|
* 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.spigot.world.manager;
|
||||||
|
|
||||||
|
import org.bukkit.Bukkit;
|
||||||
|
import org.bukkit.entity.Player;
|
||||||
|
import org.geysermc.adapters.spigot.SpigotAdapters;
|
||||||
|
import org.geysermc.adapters.spigot.SpigotWorldAdapter;
|
||||||
|
import org.geysermc.connector.network.session.GeyserSession;
|
||||||
|
import org.geysermc.connector.network.translators.world.block.BlockTranslator;
|
||||||
|
import us.myles.ViaVersion.api.Via;
|
||||||
|
import us.myles.ViaVersion.protocols.protocol1_13to1_12_2.storage.BlockStorage;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Used with ViaVersion and pre-1.13.
|
||||||
|
*/
|
||||||
|
public class GeyserSpigot1_12NativeWorldManager extends GeyserSpigot1_12WorldManager {
|
||||||
|
private final SpigotWorldAdapter adapter;
|
||||||
|
|
||||||
|
public GeyserSpigot1_12NativeWorldManager() {
|
||||||
|
this.adapter = SpigotAdapters.getWorldAdapter();
|
||||||
|
// Unlike post-1.13, we can't build up a cache of block states, because block entities need some special conversion
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getBlockAt(GeyserSession session, int x, int y, int z) {
|
||||||
|
Player player = Bukkit.getPlayer(session.getPlayerEntity().getUsername());
|
||||||
|
if (player == null) {
|
||||||
|
return BlockTranslator.JAVA_AIR_ID;
|
||||||
|
}
|
||||||
|
// Get block entity storage
|
||||||
|
BlockStorage storage = Via.getManager().getConnection(player.getUniqueId()).get(BlockStorage.class);
|
||||||
|
int blockId = adapter.getBlockAt(player.getWorld(), x, y, z);
|
||||||
|
return getLegacyBlock(storage, blockId, x, y, z);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,141 @@
|
||||||
|
/*
|
||||||
|
* 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.spigot.world.manager;
|
||||||
|
|
||||||
|
import com.github.steveice10.mc.protocol.data.game.chunk.Chunk;
|
||||||
|
import org.bukkit.Bukkit;
|
||||||
|
import org.bukkit.World;
|
||||||
|
import org.bukkit.block.Block;
|
||||||
|
import org.bukkit.entity.Player;
|
||||||
|
import org.geysermc.connector.network.session.GeyserSession;
|
||||||
|
import org.geysermc.connector.network.translators.world.block.BlockTranslator;
|
||||||
|
import us.myles.ViaVersion.api.Pair;
|
||||||
|
import us.myles.ViaVersion.api.Via;
|
||||||
|
import us.myles.ViaVersion.api.data.MappingData;
|
||||||
|
import us.myles.ViaVersion.api.minecraft.Position;
|
||||||
|
import us.myles.ViaVersion.api.protocol.Protocol;
|
||||||
|
import us.myles.ViaVersion.api.protocol.ProtocolRegistry;
|
||||||
|
import us.myles.ViaVersion.api.protocol.ProtocolVersion;
|
||||||
|
import us.myles.ViaVersion.protocols.protocol1_13to1_12_2.Protocol1_13To1_12_2;
|
||||||
|
import us.myles.ViaVersion.protocols.protocol1_13to1_12_2.storage.BlockStorage;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Should be used when ViaVersion is present, no NMS adapter is being used, and we are pre-1.13.
|
||||||
|
*
|
||||||
|
* You need ViaVersion to connect to an older server with the Geyser-Spigot plugin.
|
||||||
|
*/
|
||||||
|
public class GeyserSpigot1_12WorldManager extends GeyserSpigotWorldManager {
|
||||||
|
/**
|
||||||
|
* Specific mapping data for 1.12 to 1.13. Used to convert the 1.12 block into the 1.13 block state.
|
||||||
|
* (Block IDs did not change between server versions until 1.13 and after)
|
||||||
|
*/
|
||||||
|
private final MappingData mappingData1_12to1_13;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The list of all protocols from the client's version to 1.13.
|
||||||
|
*/
|
||||||
|
private final List<Pair<Integer, Protocol>> protocolList;
|
||||||
|
|
||||||
|
public GeyserSpigot1_12WorldManager() {
|
||||||
|
super(false);
|
||||||
|
this.mappingData1_12to1_13 = ProtocolRegistry.getProtocol(Protocol1_13To1_12_2.class).getMappingData();
|
||||||
|
this.protocolList = ProtocolRegistry.getProtocolPath(CLIENT_PROTOCOL_VERSION,
|
||||||
|
ProtocolVersion.v1_13.getVersion());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@SuppressWarnings("deprecation")
|
||||||
|
public int getBlockAt(GeyserSession session, int x, int y, int z) {
|
||||||
|
Player player = Bukkit.getPlayer(session.getPlayerEntity().getUsername());
|
||||||
|
if (player == null) {
|
||||||
|
return BlockTranslator.JAVA_AIR_ID;
|
||||||
|
}
|
||||||
|
// Get block entity storage
|
||||||
|
BlockStorage storage = Via.getManager().getConnection(player.getUniqueId()).get(BlockStorage.class);
|
||||||
|
Block block = player.getWorld().getBlockAt(x, y, z);
|
||||||
|
// Black magic that gets the old block state ID
|
||||||
|
int blockId = (block.getType().getId() << 4) | (block.getData() & 0xF);
|
||||||
|
return getLegacyBlock(storage, blockId, x, y, z);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @param storage ViaVersion's block entity storage (used to fix block entity state differences)
|
||||||
|
* @param blockId the pre-1.13 block id
|
||||||
|
* @param x X coordinate of block
|
||||||
|
* @param y Y coordinate of block
|
||||||
|
* @param z Z coordinate of block
|
||||||
|
* @return the block state updated to the latest Minecraft version
|
||||||
|
*/
|
||||||
|
@SuppressWarnings("deprecation")
|
||||||
|
public int getLegacyBlock(BlockStorage storage, int blockId, int x, int y, int z) {
|
||||||
|
// Convert block state from old version (1.12.2) -> 1.13 -> 1.13.1 -> 1.14 -> 1.15 -> 1.16 -> 1.16.2
|
||||||
|
blockId = mappingData1_12to1_13.getNewBlockId(blockId);
|
||||||
|
// Translate block entity differences - some information was stored in block tags and not block states
|
||||||
|
if (storage.isWelcome(blockId)) { // No getOrDefault method
|
||||||
|
BlockStorage.ReplacementData data = storage.get(new Position(x, (short) y, z));
|
||||||
|
if (data != null && data.getReplacement() != -1) {
|
||||||
|
blockId = data.getReplacement();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for (int i = protocolList.size() - 1; i >= 0; i--) {
|
||||||
|
MappingData mappingData = protocolList.get(i).getValue().getMappingData();
|
||||||
|
if (mappingData != null) {
|
||||||
|
blockId = mappingData.getNewBlockStateId(blockId);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return blockId;
|
||||||
|
}
|
||||||
|
|
||||||
|
@SuppressWarnings("deprecation")
|
||||||
|
@Override
|
||||||
|
public void getBlocksInSection(GeyserSession session, int x, int y, int z, Chunk chunk) {
|
||||||
|
Player player = Bukkit.getPlayer(session.getPlayerEntity().getUsername());
|
||||||
|
if (player == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
World world = player.getWorld();
|
||||||
|
// Get block entity storage
|
||||||
|
BlockStorage storage = Via.getManager().getConnection(player.getUniqueId()).get(BlockStorage.class);
|
||||||
|
for (int blockY = 0; blockY < 16; blockY++) { // Cache-friendly iteration order
|
||||||
|
for (int blockZ = 0; blockZ < 16; blockZ++) {
|
||||||
|
for (int blockX = 0; blockX < 16; blockX++) {
|
||||||
|
Block block = world.getBlockAt(x, y, z);
|
||||||
|
// Black magic that gets the old block state ID
|
||||||
|
int blockId = (block.getType().getId() << 4) | (block.getData() & 0xF);
|
||||||
|
chunk.set(blockX, blockY, blockZ, getLegacyBlock(storage, blockId, (x << 4) + blockX, (y << 4) + blockY, (z << 4) + blockZ));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isLegacy() {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,62 @@
|
||||||
|
/*
|
||||||
|
* 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.spigot.world.manager;
|
||||||
|
|
||||||
|
import com.github.steveice10.mc.protocol.data.game.chunk.Chunk;
|
||||||
|
import org.geysermc.connector.network.session.GeyserSession;
|
||||||
|
import org.geysermc.connector.network.translators.world.block.BlockTranslator;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Should only be used when we know {@link GeyserSpigotWorldManager#getBlockAt(GeyserSession, int, int, int)}
|
||||||
|
* cannot be accurate. Typically, this is when ViaVersion is not installed but a client still manages to connect.
|
||||||
|
* If this occurs to you somehow, please let us know!!
|
||||||
|
*/
|
||||||
|
public class GeyserSpigotFallbackWorldManager extends GeyserSpigotWorldManager {
|
||||||
|
public GeyserSpigotFallbackWorldManager() {
|
||||||
|
// Since this is pre-1.13 (and thus pre-1.15), there will never be 3D biomes.
|
||||||
|
super(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getBlockAt(GeyserSession session, int x, int y, int z) {
|
||||||
|
return BlockTranslator.JAVA_AIR_ID;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void getBlocksInSection(GeyserSession session, int x, int y, int z, Chunk chunk) {
|
||||||
|
// Do nothing, since we can't do anything with the chunk
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean hasMoreBlockDataThanChunkCache() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isLegacy() {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
|
@ -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.spigot.world.manager;
|
||||||
|
|
||||||
|
import com.github.steveice10.mc.protocol.MinecraftConstants;
|
||||||
|
import it.unimi.dsi.fastutil.ints.Int2IntMap;
|
||||||
|
import it.unimi.dsi.fastutil.ints.Int2IntOpenHashMap;
|
||||||
|
import it.unimi.dsi.fastutil.ints.IntList;
|
||||||
|
import org.geysermc.connector.network.session.GeyserSession;
|
||||||
|
import org.geysermc.platform.spigot.GeyserSpigotPlugin;
|
||||||
|
import us.myles.ViaVersion.api.Pair;
|
||||||
|
import us.myles.ViaVersion.api.data.MappingData;
|
||||||
|
import us.myles.ViaVersion.api.protocol.Protocol;
|
||||||
|
import us.myles.ViaVersion.api.protocol.ProtocolRegistry;
|
||||||
|
import us.myles.ViaVersion.api.protocol.ProtocolVersion;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Used when block IDs need to be translated to the latest version
|
||||||
|
*/
|
||||||
|
public class GeyserSpigotLegacyNativeWorldManager extends GeyserSpigotNativeWorldManager {
|
||||||
|
|
||||||
|
private final Int2IntMap oldToNewBlockId;
|
||||||
|
|
||||||
|
public GeyserSpigotLegacyNativeWorldManager(GeyserSpigotPlugin plugin, boolean use3dBiomes) {
|
||||||
|
super(use3dBiomes);
|
||||||
|
IntList allBlockStates = adapter.getAllBlockStates();
|
||||||
|
oldToNewBlockId = new Int2IntOpenHashMap(allBlockStates.size());
|
||||||
|
ProtocolVersion serverVersion = plugin.getServerProtocolVersion();
|
||||||
|
List<Pair<Integer, Protocol>> protocolList = ProtocolRegistry.getProtocolPath(MinecraftConstants.PROTOCOL_VERSION,
|
||||||
|
serverVersion.getVersion());
|
||||||
|
for (int oldBlockId : allBlockStates) {
|
||||||
|
int newBlockId = oldBlockId;
|
||||||
|
// protocolList should *not* be null; we checked for that before initializing this class
|
||||||
|
for (int i = protocolList.size() - 1; i >= 0; i--) {
|
||||||
|
MappingData mappingData = protocolList.get(i).getValue().getMappingData();
|
||||||
|
if (mappingData != null) {
|
||||||
|
newBlockId = mappingData.getNewBlockStateId(newBlockId);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
oldToNewBlockId.put(oldBlockId, newBlockId);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getBlockAt(GeyserSession session, int x, int y, int z) {
|
||||||
|
int nativeBlockId = super.getBlockAt(session, x, y, z);
|
||||||
|
return oldToNewBlockId.getOrDefault(nativeBlockId, nativeBlockId);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isLegacy() {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,51 @@
|
||||||
|
/*
|
||||||
|
* 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.spigot.world.manager;
|
||||||
|
|
||||||
|
import org.bukkit.Bukkit;
|
||||||
|
import org.bukkit.entity.Player;
|
||||||
|
import org.geysermc.adapters.spigot.SpigotAdapters;
|
||||||
|
import org.geysermc.adapters.spigot.SpigotWorldAdapter;
|
||||||
|
import org.geysermc.connector.network.session.GeyserSession;
|
||||||
|
import org.geysermc.connector.network.translators.world.block.BlockTranslator;
|
||||||
|
|
||||||
|
public class GeyserSpigotNativeWorldManager extends GeyserSpigotWorldManager {
|
||||||
|
protected final SpigotWorldAdapter adapter;
|
||||||
|
|
||||||
|
public GeyserSpigotNativeWorldManager(boolean use3dBiomes) {
|
||||||
|
super(use3dBiomes);
|
||||||
|
adapter = SpigotAdapters.getWorldAdapter();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getBlockAt(GeyserSession session, int x, int y, int z) {
|
||||||
|
Player player = Bukkit.getPlayer(session.getPlayerEntity().getUsername());
|
||||||
|
if (player == null) {
|
||||||
|
return BlockTranslator.JAVA_AIR_ID;
|
||||||
|
}
|
||||||
|
return adapter.getBlockAt(player.getWorld(), x, y, z);
|
||||||
|
}
|
||||||
|
}
|
|
@ -23,9 +23,10 @@
|
||||||
* @link https://github.com/GeyserMC/Geyser
|
* @link https://github.com/GeyserMC/Geyser
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package org.geysermc.platform.spigot.world;
|
package org.geysermc.platform.spigot.world.manager;
|
||||||
|
|
||||||
import com.fasterxml.jackson.databind.JsonNode;
|
import com.fasterxml.jackson.databind.JsonNode;
|
||||||
|
import com.github.steveice10.mc.protocol.MinecraftConstants;
|
||||||
import com.github.steveice10.mc.protocol.data.game.chunk.Chunk;
|
import com.github.steveice10.mc.protocol.data.game.chunk.Chunk;
|
||||||
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;
|
||||||
|
@ -33,6 +34,7 @@ import org.bukkit.Bukkit;
|
||||||
import org.bukkit.World;
|
import org.bukkit.World;
|
||||||
import org.bukkit.block.Biome;
|
import org.bukkit.block.Biome;
|
||||||
import org.bukkit.block.Block;
|
import org.bukkit.block.Block;
|
||||||
|
import org.bukkit.block.data.BlockData;
|
||||||
import org.bukkit.entity.Player;
|
import org.bukkit.entity.Player;
|
||||||
import org.geysermc.connector.GeyserConnector;
|
import org.geysermc.connector.GeyserConnector;
|
||||||
import org.geysermc.connector.network.session.GeyserSession;
|
import org.geysermc.connector.network.session.GeyserSession;
|
||||||
|
@ -41,20 +43,22 @@ import org.geysermc.connector.network.translators.world.block.BlockTranslator;
|
||||||
import org.geysermc.connector.utils.FileUtils;
|
import org.geysermc.connector.utils.FileUtils;
|
||||||
import org.geysermc.connector.utils.GameRule;
|
import org.geysermc.connector.utils.GameRule;
|
||||||
import org.geysermc.connector.utils.LanguageUtils;
|
import org.geysermc.connector.utils.LanguageUtils;
|
||||||
import us.myles.ViaVersion.protocols.protocol1_13_1to1_13.Protocol1_13_1To1_13;
|
|
||||||
import us.myles.ViaVersion.protocols.protocol1_16_2to1_16_1.data.MappingData;
|
|
||||||
|
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
|
|
||||||
public class GeyserSpigotWorldManager extends GeyserWorldManager {
|
|
||||||
|
|
||||||
private final boolean isLegacy;
|
|
||||||
private final boolean use3dBiomes;
|
|
||||||
/**
|
/**
|
||||||
* You need ViaVersion to connect to an older server with Geyser.
|
* The base world manager to use when there is no supported NMS revision
|
||||||
* 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;
|
public class GeyserSpigotWorldManager extends GeyserWorldManager {
|
||||||
|
/**
|
||||||
|
* The current client protocol version for ViaVersion usage.
|
||||||
|
*/
|
||||||
|
protected static final int CLIENT_PROTOCOL_VERSION = MinecraftConstants.PROTOCOL_VERSION;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Whether the server is pre-1.16 and therefore does not support 3D biomes on an API level guaranteed.
|
||||||
|
*/
|
||||||
|
private final boolean use3dBiomes;
|
||||||
/**
|
/**
|
||||||
* Stores a list of {@link Biome} ordinal numbers to Minecraft biome numeric IDs.
|
* Stores a list of {@link Biome} ordinal numbers to Minecraft biome numeric IDs.
|
||||||
*
|
*
|
||||||
|
@ -68,10 +72,8 @@ public class GeyserSpigotWorldManager extends GeyserWorldManager {
|
||||||
*/
|
*/
|
||||||
private final Int2IntMap biomeToIdMap = new Int2IntOpenHashMap(Biome.values().length);
|
private final Int2IntMap biomeToIdMap = new Int2IntOpenHashMap(Biome.values().length);
|
||||||
|
|
||||||
public GeyserSpigotWorldManager(boolean isLegacy, boolean use3dBiomes, boolean isViaVersion) {
|
public GeyserSpigotWorldManager(boolean use3dBiomes) {
|
||||||
this.isLegacy = isLegacy;
|
|
||||||
this.use3dBiomes = use3dBiomes;
|
this.use3dBiomes = use3dBiomes;
|
||||||
this.isViaVersion = isViaVersion;
|
|
||||||
|
|
||||||
// Load the values into the biome-to-ID map
|
// Load the values into the biome-to-ID map
|
||||||
InputStream biomeStream = FileUtils.getResource("biomes.json");
|
InputStream biomeStream = FileUtils.getResource("biomes.json");
|
||||||
|
@ -83,8 +85,9 @@ public class GeyserSpigotWorldManager extends GeyserWorldManager {
|
||||||
}
|
}
|
||||||
// Only load in the biomes that are present in this version of Minecraft
|
// Only load in the biomes that are present in this version of Minecraft
|
||||||
for (Biome enumBiome : Biome.values()) {
|
for (Biome enumBiome : Biome.values()) {
|
||||||
if (biomes.has(enumBiome.toString())) {
|
JsonNode biome = biomes.get(enumBiome.toString());
|
||||||
biomeToIdMap.put(enumBiome.ordinal(), biomes.get(enumBiome.toString()).intValue());
|
if (biome != null) {
|
||||||
|
biomeToIdMap.put(enumBiome.ordinal(), biome.intValue());
|
||||||
} else {
|
} else {
|
||||||
GeyserConnector.getInstance().getLogger().debug("No biome mapping found for " + enumBiome.toString() +
|
GeyserConnector.getInstance().getLogger().debug("No biome mapping found for " + enumBiome.toString() +
|
||||||
", defaulting to 0");
|
", defaulting to 0");
|
||||||
|
@ -96,75 +99,30 @@ public class GeyserSpigotWorldManager extends GeyserWorldManager {
|
||||||
@Override
|
@Override
|
||||||
public int getBlockAt(GeyserSession session, int x, int y, int z) {
|
public int getBlockAt(GeyserSession session, int x, int y, int z) {
|
||||||
Player bukkitPlayer;
|
Player bukkitPlayer;
|
||||||
if ((this.isLegacy && !this.isViaVersion)
|
if ((bukkitPlayer = Bukkit.getPlayer(session.getPlayerEntity().getUsername())) == null) {
|
||||||
|| session.getPlayerEntity() == null
|
return BlockTranslator.JAVA_AIR_ID;
|
||||||
|| (bukkitPlayer = Bukkit.getPlayer(session.getPlayerEntity().getUsername())) == null) {
|
|
||||||
return BlockTranslator.AIR;
|
|
||||||
}
|
}
|
||||||
World world = bukkitPlayer.getWorld();
|
World world = bukkitPlayer.getWorld();
|
||||||
if (isLegacy) {
|
return BlockTranslator.getJavaIdBlockMap().getOrDefault(world.getBlockAt(x, y, z).getBlockData().getAsString(), BlockTranslator.JAVA_AIR_ID);
|
||||||
return getLegacyBlock(session, x, y, z, true);
|
|
||||||
}
|
|
||||||
//TODO possibly: detect server version for all versions and use ViaVersion for block state mappings like below
|
|
||||||
return BlockTranslator.getJavaIdBlockMap().getOrDefault(world.getBlockAt(x, y, z).getBlockData().getAsString(), 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static int getLegacyBlock(GeyserSession session, int x, int y, int z, boolean isViaVersion) {
|
|
||||||
if (isViaVersion) {
|
|
||||||
return getLegacyBlock(Bukkit.getPlayer(session.getPlayerEntity().getUsername()).getWorld(), x, y, z, true);
|
|
||||||
} else {
|
|
||||||
return BlockTranslator.AIR;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@SuppressWarnings("deprecation")
|
|
||||||
public static int getLegacyBlock(World world, int x, int y, int z, boolean isViaVersion) {
|
|
||||||
if (isViaVersion) {
|
|
||||||
Block block = world.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 -> 1.16 -> 1.16.2
|
|
||||||
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);
|
|
||||||
int fifteenBlockId = us.myles.ViaVersion.protocols.protocol1_15to1_14_4.data.MappingData.blockStateMappings.getNewId(fourteenBlockId);
|
|
||||||
int sixteenBlockId = us.myles.ViaVersion.protocols.protocol1_16to1_15_2.data.MappingData.blockStateMappings.getNewId(fifteenBlockId);
|
|
||||||
return MappingData.blockStateMappings.getNewId(sixteenBlockId);
|
|
||||||
} else {
|
|
||||||
return BlockTranslator.AIR;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void getBlocksInSection(GeyserSession session, int x, int y, int z, Chunk chunk) {
|
public void getBlocksInSection(GeyserSession session, int x, int y, int z, Chunk chunk) {
|
||||||
Player bukkitPlayer;
|
Player bukkitPlayer;
|
||||||
if ((this.isLegacy && !this.isViaVersion)
|
if ((bukkitPlayer = Bukkit.getPlayer(session.getPlayerEntity().getUsername())) == null) {
|
||||||
|| session.getPlayerEntity() == null
|
|
||||||
|| (bukkitPlayer = Bukkit.getPlayer(session.getPlayerEntity().getUsername())) == null) {
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
World world = bukkitPlayer.getWorld();
|
World world = bukkitPlayer.getWorld();
|
||||||
if (this.isLegacy) {
|
|
||||||
for (int blockY = 0; blockY < 16; blockY++) { // Cache-friendly iteration order
|
|
||||||
for (int blockZ = 0; blockZ < 16; blockZ++) {
|
|
||||||
for (int blockX = 0; blockX < 16; blockX++) {
|
|
||||||
chunk.set(blockX, blockY, blockZ, getLegacyBlock(world, (x << 4) + blockX, (y << 4) + blockY, (z << 4) + blockZ, true));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
//TODO: see above TODO in getBlockAt
|
|
||||||
for (int blockY = 0; blockY < 16; blockY++) { // Cache-friendly iteration order
|
for (int blockY = 0; blockY < 16; blockY++) { // Cache-friendly iteration order
|
||||||
for (int blockZ = 0; blockZ < 16; blockZ++) {
|
for (int blockZ = 0; blockZ < 16; blockZ++) {
|
||||||
for (int blockX = 0; blockX < 16; blockX++) {
|
for (int blockX = 0; blockX < 16; blockX++) {
|
||||||
Block block = world.getBlockAt((x << 4) + blockX, (y << 4) + blockY, (z << 4) + blockZ);
|
Block block = world.getBlockAt((x << 4) + blockX, (y << 4) + blockY, (z << 4) + blockZ);
|
||||||
int id = BlockTranslator.getJavaIdBlockMap().getOrDefault(block.getBlockData().getAsString(), 0);
|
int id = BlockTranslator.getJavaIdBlockMap().getOrDefault(block.getBlockData().getAsString(), BlockTranslator.JAVA_AIR_ID);
|
||||||
chunk.set(blockX, blockY, blockZ, id);
|
chunk.set(blockX, blockY, blockZ, id);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean hasMoreBlockDataThanChunkCache() {
|
public boolean hasMoreBlockDataThanChunkCache() {
|
||||||
|
@ -222,4 +180,16 @@ public class GeyserSpigotWorldManager extends GeyserWorldManager {
|
||||||
public boolean hasPermission(GeyserSession session, String permission) {
|
public boolean hasPermission(GeyserSession session, String permission) {
|
||||||
return Bukkit.getPlayer(session.getPlayerEntity().getUsername()).hasPermission(permission);
|
return Bukkit.getPlayer(session.getPlayerEntity().getUsername()).hasPermission(permission);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This must be set to true if we are pre-1.13, and {@link BlockData#getAsString() does not exist}.
|
||||||
|
*
|
||||||
|
* This should be set to true if we are post-1.13 but before the latest version, and we should convert the old block state id
|
||||||
|
* to the current one.
|
||||||
|
*
|
||||||
|
* @return whether there is a difference between client block state and server block state that requires extra processing
|
||||||
|
*/
|
||||||
|
public boolean isLegacy() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
}
|
}
|
|
@ -6,15 +6,15 @@
|
||||||
<parent>
|
<parent>
|
||||||
<groupId>org.geysermc</groupId>
|
<groupId>org.geysermc</groupId>
|
||||||
<artifactId>bootstrap-parent</artifactId>
|
<artifactId>bootstrap-parent</artifactId>
|
||||||
<version>1.1.0</version>
|
<version>1.2.0-SNAPSHOT</version>
|
||||||
<relativePath>../</relativePath>
|
|
||||||
</parent>
|
</parent>
|
||||||
<artifactId>bootstrap-sponge</artifactId>
|
<artifactId>bootstrap-sponge</artifactId>
|
||||||
|
|
||||||
<dependencies>
|
<dependencies>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.geysermc</groupId>
|
<groupId>org.geysermc</groupId>
|
||||||
<artifactId>connector</artifactId>
|
<artifactId>connector</artifactId>
|
||||||
<version>1.1.0</version>
|
<version>1.2.0-SNAPSHOT</version>
|
||||||
<scope>compile</scope>
|
<scope>compile</scope>
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
|
|
|
@ -38,20 +38,18 @@ import org.spongepowered.api.network.status.StatusClient;
|
||||||
import org.spongepowered.api.profile.GameProfile;
|
import org.spongepowered.api.profile.GameProfile;
|
||||||
|
|
||||||
import java.lang.reflect.Method;
|
import java.lang.reflect.Method;
|
||||||
import java.net.Inet4Address;
|
|
||||||
import java.net.InetSocketAddress;
|
import java.net.InetSocketAddress;
|
||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
|
|
||||||
public class GeyserSpongePingPassthrough implements IGeyserPingPassthrough {
|
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 final Cause CAUSE = Cause.of(EventContext.empty(), Sponge.getServer());
|
||||||
|
|
||||||
private static Method SpongeStatusResponse_create;
|
private static Method SpongeStatusResponse_create;
|
||||||
|
|
||||||
@SuppressWarnings({"unchecked", "rawtypes"})
|
@SuppressWarnings({"unchecked", "rawtypes"})
|
||||||
@Override
|
@Override
|
||||||
public GeyserPingInfo getPingInformation() {
|
public GeyserPingInfo getPingInformation(InetSocketAddress inetSocketAddress) {
|
||||||
// come on Sponge, this is in commons, why not expose it :(
|
// come on Sponge, this is in commons, why not expose it :(
|
||||||
ClientPingServerEvent event;
|
ClientPingServerEvent event;
|
||||||
try {
|
try {
|
||||||
|
@ -62,7 +60,7 @@ public class GeyserSpongePingPassthrough implements IGeyserPingPassthrough {
|
||||||
}
|
}
|
||||||
|
|
||||||
Object response = SpongeStatusResponse_create.invoke(null, Sponge.getServer());
|
Object response = SpongeStatusResponse_create.invoke(null, Sponge.getServer());
|
||||||
event = SpongeEventFactory.createClientPingServerEvent(CAUSE, STATUS_CLIENT, (ClientPingServerEvent.Response) response);
|
event = SpongeEventFactory.createClientPingServerEvent(CAUSE, new GeyserStatusClient(inetSocketAddress), (ClientPingServerEvent.Response) response);
|
||||||
} catch (ReflectiveOperationException e) {
|
} catch (ReflectiveOperationException e) {
|
||||||
throw new RuntimeException(e);
|
throw new RuntimeException(e);
|
||||||
}
|
}
|
||||||
|
@ -87,11 +85,15 @@ public class GeyserSpongePingPassthrough implements IGeyserPingPassthrough {
|
||||||
@SuppressWarnings("NullableProblems")
|
@SuppressWarnings("NullableProblems")
|
||||||
private static class GeyserStatusClient implements StatusClient {
|
private static class GeyserStatusClient implements StatusClient {
|
||||||
|
|
||||||
private static final InetSocketAddress FAKE_REMOTE = new InetSocketAddress(Inet4Address.getLoopbackAddress(), 69);
|
private final InetSocketAddress remote;
|
||||||
|
|
||||||
|
public GeyserStatusClient(InetSocketAddress remote) {
|
||||||
|
this.remote = remote;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public InetSocketAddress getAddress() {
|
public InetSocketAddress getAddress() {
|
||||||
return FAKE_REMOTE;
|
return this.remote;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -26,10 +26,10 @@
|
||||||
package org.geysermc.platform.sponge;
|
package org.geysermc.platform.sponge;
|
||||||
|
|
||||||
import com.google.inject.Inject;
|
import com.google.inject.Inject;
|
||||||
|
import org.geysermc.common.PlatformType;
|
||||||
import org.geysermc.connector.GeyserConnector;
|
import org.geysermc.connector.GeyserConnector;
|
||||||
import org.geysermc.connector.bootstrap.GeyserBootstrap;
|
import org.geysermc.connector.bootstrap.GeyserBootstrap;
|
||||||
import org.geysermc.connector.command.CommandManager;
|
import org.geysermc.connector.command.CommandManager;
|
||||||
import org.geysermc.connector.common.PlatformType;
|
|
||||||
import org.geysermc.connector.configuration.GeyserConfiguration;
|
import org.geysermc.connector.configuration.GeyserConfiguration;
|
||||||
import org.geysermc.connector.dump.BootstrapDumpInfo;
|
import org.geysermc.connector.dump.BootstrapDumpInfo;
|
||||||
import org.geysermc.connector.ping.GeyserLegacyPingPassthrough;
|
import org.geysermc.connector.ping.GeyserLegacyPingPassthrough;
|
||||||
|
|
|
@ -70,7 +70,7 @@ public class GeyserSpongeCommandExecutor implements CommandCallable {
|
||||||
@Override
|
@Override
|
||||||
public List<String> getSuggestions(CommandSource source, String arguments, @Nullable Location<World> targetPosition) throws CommandException {
|
public List<String> getSuggestions(CommandSource source, String arguments, @Nullable Location<World> targetPosition) throws CommandException {
|
||||||
if (arguments.split(" ").length == 1) {
|
if (arguments.split(" ").length == 1) {
|
||||||
return Arrays.asList("?", "help", "reload", "shutdown", "stop");
|
return connector.getCommandManager().getCommandNames();
|
||||||
}
|
}
|
||||||
return new ArrayList<>();
|
return new ArrayList<>();
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,15 +6,15 @@
|
||||||
<parent>
|
<parent>
|
||||||
<groupId>org.geysermc</groupId>
|
<groupId>org.geysermc</groupId>
|
||||||
<artifactId>bootstrap-parent</artifactId>
|
<artifactId>bootstrap-parent</artifactId>
|
||||||
<version>1.1.0</version>
|
<version>1.2.0-SNAPSHOT</version>
|
||||||
<relativePath>../</relativePath>
|
|
||||||
</parent>
|
</parent>
|
||||||
<artifactId>bootstrap-standalone</artifactId>
|
<artifactId>bootstrap-standalone</artifactId>
|
||||||
|
|
||||||
<dependencies>
|
<dependencies>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.geysermc</groupId>
|
<groupId>org.geysermc</groupId>
|
||||||
<artifactId>connector</artifactId>
|
<artifactId>connector</artifactId>
|
||||||
<version>1.1.0</version>
|
<version>1.2.0-SNAPSHOT</version>
|
||||||
<scope>compile</scope>
|
<scope>compile</scope>
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
|
|
|
@ -25,17 +25,23 @@
|
||||||
|
|
||||||
package org.geysermc.platform.standalone;
|
package org.geysermc.platform.standalone;
|
||||||
|
|
||||||
|
import com.fasterxml.jackson.databind.BeanDescription;
|
||||||
|
import com.fasterxml.jackson.databind.JavaType;
|
||||||
|
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||||
|
import com.fasterxml.jackson.databind.introspect.AnnotatedField;
|
||||||
|
import com.fasterxml.jackson.databind.introspect.BeanPropertyDefinition;
|
||||||
import lombok.Getter;
|
import lombok.Getter;
|
||||||
import net.minecrell.terminalconsole.TerminalConsoleAppender;
|
import net.minecrell.terminalconsole.TerminalConsoleAppender;
|
||||||
import org.apache.logging.log4j.LogManager;
|
import org.apache.logging.log4j.LogManager;
|
||||||
import org.apache.logging.log4j.core.Appender;
|
import org.apache.logging.log4j.core.Appender;
|
||||||
import org.apache.logging.log4j.core.Logger;
|
import org.apache.logging.log4j.core.Logger;
|
||||||
import org.apache.logging.log4j.core.appender.ConsoleAppender;
|
import org.apache.logging.log4j.core.appender.ConsoleAppender;
|
||||||
|
import org.geysermc.common.PlatformType;
|
||||||
import org.geysermc.connector.GeyserConnector;
|
import org.geysermc.connector.GeyserConnector;
|
||||||
import org.geysermc.connector.bootstrap.GeyserBootstrap;
|
import org.geysermc.connector.bootstrap.GeyserBootstrap;
|
||||||
import org.geysermc.connector.command.CommandManager;
|
import org.geysermc.connector.command.CommandManager;
|
||||||
import org.geysermc.connector.common.PlatformType;
|
|
||||||
import org.geysermc.connector.configuration.GeyserConfiguration;
|
import org.geysermc.connector.configuration.GeyserConfiguration;
|
||||||
|
import org.geysermc.connector.configuration.GeyserJacksonConfiguration;
|
||||||
import org.geysermc.connector.dump.BootstrapDumpInfo;
|
import org.geysermc.connector.dump.BootstrapDumpInfo;
|
||||||
import org.geysermc.connector.ping.GeyserLegacyPingPassthrough;
|
import org.geysermc.connector.ping.GeyserLegacyPingPassthrough;
|
||||||
import org.geysermc.connector.ping.IGeyserPingPassthrough;
|
import org.geysermc.connector.ping.IGeyserPingPassthrough;
|
||||||
|
@ -50,7 +56,8 @@ import java.lang.reflect.Method;
|
||||||
import java.nio.file.Path;
|
import java.nio.file.Path;
|
||||||
import java.nio.file.Paths;
|
import java.nio.file.Paths;
|
||||||
import java.text.MessageFormat;
|
import java.text.MessageFormat;
|
||||||
import java.util.UUID;
|
import java.util.*;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
public class GeyserStandaloneBootstrap implements GeyserBootstrap {
|
public class GeyserStandaloneBootstrap implements GeyserBootstrap {
|
||||||
|
|
||||||
|
@ -67,6 +74,9 @@ public class GeyserStandaloneBootstrap implements GeyserBootstrap {
|
||||||
|
|
||||||
private GeyserConnector connector;
|
private GeyserConnector connector;
|
||||||
|
|
||||||
|
private static final ObjectMapper OBJECT_MAPPER = new ObjectMapper();
|
||||||
|
|
||||||
|
private static final Map<String, String> argsConfigKeys = new HashMap<>();
|
||||||
|
|
||||||
public static void main(String[] args) {
|
public static void main(String[] args) {
|
||||||
GeyserStandaloneBootstrap bootstrap = new GeyserStandaloneBootstrap();
|
GeyserStandaloneBootstrap bootstrap = new GeyserStandaloneBootstrap();
|
||||||
|
@ -74,6 +84,8 @@ public class GeyserStandaloneBootstrap implements GeyserBootstrap {
|
||||||
boolean useGuiOpts = bootstrap.useGui;
|
boolean useGuiOpts = bootstrap.useGui;
|
||||||
String configFilenameOpt = bootstrap.configFilename;
|
String configFilenameOpt = bootstrap.configFilename;
|
||||||
|
|
||||||
|
List<BeanPropertyDefinition> availableProperties = getPOJOForClass(GeyserJacksonConfiguration.class);
|
||||||
|
|
||||||
for (int i = 0; i < args.length; i++) {
|
for (int i = 0; i < args.length; i++) {
|
||||||
// By default, standalone Geyser will check if it should open the GUI based on if the GUI is null
|
// By default, standalone Geyser will check if it should open the GUI based on if the GUI is null
|
||||||
// Optionally, you can force the use of a GUI or no GUI by specifying args
|
// Optionally, you can force the use of a GUI or no GUI by specifying args
|
||||||
|
@ -91,11 +103,11 @@ public class GeyserStandaloneBootstrap implements GeyserBootstrap {
|
||||||
case "--config":
|
case "--config":
|
||||||
case "-c":
|
case "-c":
|
||||||
if (i >= args.length - 1) {
|
if (i >= args.length - 1) {
|
||||||
System.err.println(MessageFormat.format(LanguageUtils.getLocaleStringLog("geyser.bootstrap.args.confignotspecified"), "-c"));
|
System.err.println(MessageFormat.format(LanguageUtils.getLocaleStringLog("geyser.bootstrap.args.config_not_specified"), "-c"));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
configFilenameOpt = args[i+1]; i++;
|
configFilenameOpt = args[i+1]; i++;
|
||||||
System.out.println(MessageFormat.format(LanguageUtils.getLocaleStringLog("geyser.bootstrap.args.configspecified"), configFilenameOpt));
|
System.out.println(MessageFormat.format(LanguageUtils.getLocaleStringLog("geyser.bootstrap.args.config_specified"), configFilenameOpt));
|
||||||
break;
|
break;
|
||||||
case "--help":
|
case "--help":
|
||||||
case "-h":
|
case "-h":
|
||||||
|
@ -106,8 +118,43 @@ public class GeyserStandaloneBootstrap implements GeyserBootstrap {
|
||||||
System.out.println(" --gui, --nogui " + LanguageUtils.getLocaleStringLog("geyser.bootstrap.args.gui"));
|
System.out.println(" --gui, --nogui " + LanguageUtils.getLocaleStringLog("geyser.bootstrap.args.gui"));
|
||||||
return;
|
return;
|
||||||
default:
|
default:
|
||||||
String badArgMsg = LanguageUtils.getLocaleStringLog("geyser.bootstrap.args.unrecognised");
|
// We have likely added a config option argument
|
||||||
System.err.println(MessageFormat.format(badArgMsg, arg));
|
if (arg.startsWith("--")) {
|
||||||
|
// Split the argument by an =
|
||||||
|
String[] argParts = arg.substring(2).split("=");
|
||||||
|
if (argParts.length == 2) {
|
||||||
|
// Split the config key by . to allow for nested options
|
||||||
|
String[] configKeyParts = argParts[0].split("\\.");
|
||||||
|
|
||||||
|
// Loop the possible config options to check the passed key is valid
|
||||||
|
boolean found = false;
|
||||||
|
for (BeanPropertyDefinition property : availableProperties) {
|
||||||
|
if (configKeyParts[0].equals(property.getName())) {
|
||||||
|
if (configKeyParts.length > 1) {
|
||||||
|
// Loop sub-section options to check the passed key is valid
|
||||||
|
for (BeanPropertyDefinition subProperty : getPOJOForClass(property.getRawPrimaryType())) {
|
||||||
|
if (configKeyParts[1].equals(subProperty.getName())) {
|
||||||
|
found = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
found = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add the found key to the stored list for later usage
|
||||||
|
if (found) {
|
||||||
|
argsConfigKeys.put(argParts[0], argParts[1]);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
System.err.println(LanguageUtils.getLocaleStringLog("geyser.bootstrap.args.unrecognised", arg));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -148,13 +195,21 @@ public class GeyserStandaloneBootstrap implements GeyserBootstrap {
|
||||||
try {
|
try {
|
||||||
File configFile = FileUtils.fileOrCopiedFromResource(new File(configFilename), "config.yml", (x) -> x.replaceAll("generateduuid", UUID.randomUUID().toString()));
|
File configFile = FileUtils.fileOrCopiedFromResource(new File(configFilename), "config.yml", (x) -> x.replaceAll("generateduuid", UUID.randomUUID().toString()));
|
||||||
geyserConfig = FileUtils.loadConfig(configFile, GeyserStandaloneConfiguration.class);
|
geyserConfig = FileUtils.loadConfig(configFile, GeyserStandaloneConfiguration.class);
|
||||||
|
|
||||||
|
handleArgsConfigOptions();
|
||||||
|
|
||||||
if (this.geyserConfig.getRemote().getAddress().equalsIgnoreCase("auto")) {
|
if (this.geyserConfig.getRemote().getAddress().equalsIgnoreCase("auto")) {
|
||||||
geyserConfig.setAutoconfiguredRemote(true); // Doesn't really need to be set but /shrug
|
geyserConfig.setAutoconfiguredRemote(true); // Doesn't really need to be set but /shrug
|
||||||
geyserConfig.getRemote().setAddress("127.0.0.1");
|
geyserConfig.getRemote().setAddress("127.0.0.1");
|
||||||
}
|
}
|
||||||
} catch (IOException ex) {
|
} catch (IOException ex) {
|
||||||
geyserLogger.severe(LanguageUtils.getLocaleStringLog("geyser.config.failed"), ex);
|
geyserLogger.severe(LanguageUtils.getLocaleStringLog("geyser.config.failed"), ex);
|
||||||
System.exit(0);
|
if (gui == null) {
|
||||||
|
System.exit(1);
|
||||||
|
} else {
|
||||||
|
// Leave the process running so the GUI is still visible
|
||||||
|
return;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
GeyserConfiguration.checkGeyserConfiguration(geyserConfig, geyserLogger);
|
GeyserConfiguration.checkGeyserConfiguration(geyserConfig, geyserLogger);
|
||||||
|
|
||||||
|
@ -223,4 +278,99 @@ public class GeyserStandaloneBootstrap implements GeyserBootstrap {
|
||||||
public BootstrapDumpInfo getDumpInfo() {
|
public BootstrapDumpInfo getDumpInfo() {
|
||||||
return new GeyserStandaloneDumpInfo(this);
|
return new GeyserStandaloneDumpInfo(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the {@link BeanPropertyDefinition}s for the given class
|
||||||
|
*
|
||||||
|
* @param clazz The class to get the definitions for
|
||||||
|
* @return A list of {@link BeanPropertyDefinition} for the given class
|
||||||
|
*/
|
||||||
|
public static List<BeanPropertyDefinition> getPOJOForClass(Class<?> clazz) {
|
||||||
|
JavaType javaType = OBJECT_MAPPER.getTypeFactory().constructType(clazz);
|
||||||
|
|
||||||
|
// Introspect the given type
|
||||||
|
BeanDescription beanDescription = OBJECT_MAPPER.getSerializationConfig().introspect(javaType);
|
||||||
|
|
||||||
|
// Find properties
|
||||||
|
List<BeanPropertyDefinition> properties = beanDescription.findProperties();
|
||||||
|
|
||||||
|
// Get the ignored properties
|
||||||
|
Set<String> ignoredProperties = OBJECT_MAPPER.getSerializationConfig().getAnnotationIntrospector()
|
||||||
|
.findPropertyIgnorals(beanDescription.getClassInfo()).getIgnored();
|
||||||
|
|
||||||
|
// Filter properties removing the ignored ones
|
||||||
|
return properties.stream()
|
||||||
|
.filter(property -> !ignoredProperties.contains(property.getName()))
|
||||||
|
.collect(Collectors.toList());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set a POJO property value on an object
|
||||||
|
*
|
||||||
|
* @param property The {@link BeanPropertyDefinition} to set
|
||||||
|
* @param parentObject The object to alter
|
||||||
|
* @param value The new value of the property
|
||||||
|
*/
|
||||||
|
private static void setConfigOption(BeanPropertyDefinition property, Object parentObject, Object value) {
|
||||||
|
Object parsedValue = value;
|
||||||
|
|
||||||
|
// Change the values type if needed
|
||||||
|
if (int.class.equals(property.getRawPrimaryType())) {
|
||||||
|
parsedValue = Integer.valueOf((String) parsedValue);
|
||||||
|
} else if (boolean.class.equals(property.getRawPrimaryType())) {
|
||||||
|
parsedValue = Boolean.valueOf((String) parsedValue);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Force the value to be set
|
||||||
|
AnnotatedField field = property.getField();
|
||||||
|
field.fixAccess(true);
|
||||||
|
field.setValue(parentObject, parsedValue);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Update the loaded {@link GeyserStandaloneConfiguration} with any values passed in the command line arguments
|
||||||
|
*/
|
||||||
|
private void handleArgsConfigOptions() {
|
||||||
|
// Get the available properties from the class
|
||||||
|
List<BeanPropertyDefinition> availableProperties = getPOJOForClass(GeyserJacksonConfiguration.class);
|
||||||
|
|
||||||
|
for (Map.Entry<String, String> configKey : argsConfigKeys.entrySet()) {
|
||||||
|
String[] configKeyParts = configKey.getKey().split("\\.");
|
||||||
|
|
||||||
|
// Loop over the properties looking for any matches against the stored one from the argument
|
||||||
|
for (BeanPropertyDefinition property : availableProperties) {
|
||||||
|
if (configKeyParts[0].equals(property.getName())) {
|
||||||
|
if (configKeyParts.length > 1) {
|
||||||
|
// Loop through the sub property if the first part matches
|
||||||
|
for (BeanPropertyDefinition subProperty : getPOJOForClass(property.getRawPrimaryType())) {
|
||||||
|
if (configKeyParts[1].equals(subProperty.getName())) {
|
||||||
|
geyserLogger.info(LanguageUtils.getLocaleStringLog("geyser.bootstrap.args.set_config_option", configKey.getKey(), configKey.getValue()));
|
||||||
|
|
||||||
|
// Set the sub property value on the config
|
||||||
|
try {
|
||||||
|
Object subConfig = property.getGetter().callOn(geyserConfig);
|
||||||
|
setConfigOption(subProperty, subConfig, configKey.getValue());
|
||||||
|
} catch (Exception e) {
|
||||||
|
geyserLogger.error("Failed to set config option: " + property.getFullName());
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
geyserLogger.info(LanguageUtils.getLocaleStringLog("geyser.bootstrap.args.set_config_option", configKey.getKey(), configKey.getValue()));
|
||||||
|
|
||||||
|
// Set the property value on the config
|
||||||
|
try {
|
||||||
|
setConfigOption(property, geyserConfig, configKey.getValue());
|
||||||
|
} catch (Exception e) {
|
||||||
|
geyserLogger.error("Failed to set config option: " + property.getFullName());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -261,14 +261,30 @@ public class GeyserStandaloneGUI {
|
||||||
|
|
||||||
for (Map.Entry<String, GeyserCommand> command : geyserCommandManager.getCommands().entrySet()) {
|
for (Map.Entry<String, GeyserCommand> command : geyserCommandManager.getCommands().entrySet()) {
|
||||||
// Remove the offhand command and any alias commands to prevent duplicates in the list
|
// Remove the offhand command and any alias commands to prevent duplicates in the list
|
||||||
if ("offhand".equals(command.getValue().getName()) || command.getValue().getAliases().contains(command.getKey())) {
|
if (!command.getValue().isExecutableOnConsole() || command.getValue().getAliases().contains(command.getKey())) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create the button that runs the command
|
// Create the button that runs the command
|
||||||
JMenuItem commandButton = new JMenuItem(command.getValue().getName());
|
boolean hasSubCommands = command.getValue().hasSubCommands();
|
||||||
|
// Add an extra menu if there are more commands that can be run
|
||||||
|
JMenuItem commandButton = hasSubCommands ? new JMenu(command.getValue().getName()) : new JMenuItem(command.getValue().getName());
|
||||||
commandButton.getAccessibleContext().setAccessibleDescription(command.getValue().getDescription());
|
commandButton.getAccessibleContext().setAccessibleDescription(command.getValue().getDescription());
|
||||||
|
if (!hasSubCommands) {
|
||||||
commandButton.addActionListener(e -> command.getValue().execute(geyserStandaloneLogger, new String[]{ }));
|
commandButton.addActionListener(e -> command.getValue().execute(geyserStandaloneLogger, new String[]{ }));
|
||||||
|
} else {
|
||||||
|
// Add a submenu that's the same name as the menu can't be pressed
|
||||||
|
JMenuItem otherCommandButton = new JMenuItem(command.getValue().getName());
|
||||||
|
otherCommandButton.getAccessibleContext().setAccessibleDescription(command.getValue().getDescription());
|
||||||
|
otherCommandButton.addActionListener(e -> command.getValue().execute(geyserStandaloneLogger, new String[]{ }));
|
||||||
|
commandButton.add(otherCommandButton);
|
||||||
|
// Add a menu option for all possible subcommands
|
||||||
|
for (String subCommandName : command.getValue().getSubCommands()) {
|
||||||
|
JMenuItem item = new JMenuItem(subCommandName);
|
||||||
|
item.addActionListener(e -> command.getValue().execute(geyserStandaloneLogger, new String[]{subCommandName}));
|
||||||
|
commandButton.add(item);
|
||||||
|
}
|
||||||
|
}
|
||||||
commandsMenu.add(commandButton);
|
commandsMenu.add(commandButton);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -291,7 +307,7 @@ public class GeyserStandaloneGUI {
|
||||||
playerTableModel.getDataVector().removeAllElements();
|
playerTableModel.getDataVector().removeAllElements();
|
||||||
|
|
||||||
for (GeyserSession player : GeyserConnector.getInstance().getPlayers()) {
|
for (GeyserSession player : GeyserConnector.getInstance().getPlayers()) {
|
||||||
Vector row = new Vector();
|
Vector<String> row = new Vector<>();
|
||||||
row.add(player.getSocketAddress().getHostName());
|
row.add(player.getSocketAddress().getHostName());
|
||||||
row.add(player.getPlayerEntity().getUsername());
|
row.add(player.getPlayerEntity().getUsername());
|
||||||
|
|
||||||
|
|
|
@ -6,21 +6,21 @@
|
||||||
<parent>
|
<parent>
|
||||||
<groupId>org.geysermc</groupId>
|
<groupId>org.geysermc</groupId>
|
||||||
<artifactId>bootstrap-parent</artifactId>
|
<artifactId>bootstrap-parent</artifactId>
|
||||||
<version>1.1.0</version>
|
<version>1.2.0-SNAPSHOT</version>
|
||||||
<relativePath>../</relativePath>
|
|
||||||
</parent>
|
</parent>
|
||||||
<artifactId>bootstrap-velocity</artifactId>
|
<artifactId>bootstrap-velocity</artifactId>
|
||||||
|
|
||||||
<dependencies>
|
<dependencies>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.geysermc</groupId>
|
<groupId>org.geysermc</groupId>
|
||||||
<artifactId>connector</artifactId>
|
<artifactId>connector</artifactId>
|
||||||
<version>1.1.0</version>
|
<version>1.2.0-SNAPSHOT</version>
|
||||||
<scope>compile</scope>
|
<scope>compile</scope>
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>com.velocitypowered</groupId>
|
<groupId>com.velocitypowered</groupId>
|
||||||
<artifactId>velocity-api</artifactId>
|
<artifactId>velocity-api</artifactId>
|
||||||
<version>1.0.0-SNAPSHOT</version>
|
<version>1.1.0</version>
|
||||||
<scope>provided</scope>
|
<scope>provided</scope>
|
||||||
</dependency>
|
</dependency>
|
||||||
</dependencies>
|
</dependencies>
|
||||||
|
@ -93,7 +93,16 @@
|
||||||
<artifactSet>
|
<artifactSet>
|
||||||
<excludes>
|
<excludes>
|
||||||
<exclude>com.google.code.gson:*</exclude>
|
<exclude>com.google.code.gson:*</exclude>
|
||||||
<exclude>io.netty:*</exclude>
|
<!-- Needed because Velocity provides every dependency except netty-resolver-dns -->
|
||||||
|
<exclude>io.netty:netty-transport-native-epoll:*</exclude>
|
||||||
|
<exclude>io.netty:netty-transport-native-unix-common:*</exclude>
|
||||||
|
<exclude>io.netty:netty-transport-native-kqueue:*</exclude>
|
||||||
|
<exclude>io.netty:netty-handler:*</exclude>
|
||||||
|
<exclude>io.netty:netty-common:*</exclude>
|
||||||
|
<exclude>io.netty:netty-buffer:*</exclude>
|
||||||
|
<exclude>io.netty:netty-resolver:*</exclude>
|
||||||
|
<exclude>io.netty:netty-transport:*</exclude>
|
||||||
|
<exclude>io.netty:netty-codec:*</exclude>
|
||||||
<exclude>org.slf4j:*</exclude>
|
<exclude>org.slf4j:*</exclude>
|
||||||
<exclude>org.ow2.asm:*</exclude>
|
<exclude>org.ow2.asm:*</exclude>
|
||||||
</excludes>
|
</excludes>
|
||||||
|
|
|
@ -43,15 +43,13 @@ import java.util.concurrent.ExecutionException;
|
||||||
@AllArgsConstructor
|
@AllArgsConstructor
|
||||||
public class GeyserVelocityPingPassthrough implements IGeyserPingPassthrough {
|
public class GeyserVelocityPingPassthrough implements IGeyserPingPassthrough {
|
||||||
|
|
||||||
private static final GeyserInboundConnection FAKE_INBOUND_CONNECTION = new GeyserInboundConnection();
|
|
||||||
|
|
||||||
private final ProxyServer server;
|
private final ProxyServer server;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public GeyserPingInfo getPingInformation() {
|
public GeyserPingInfo getPingInformation(InetSocketAddress inetSocketAddress) {
|
||||||
ProxyPingEvent event;
|
ProxyPingEvent event;
|
||||||
try {
|
try {
|
||||||
event = server.getEventManager().fire(new ProxyPingEvent(FAKE_INBOUND_CONNECTION, ServerPing.builder()
|
event = server.getEventManager().fire(new ProxyPingEvent(new GeyserInboundConnection(inetSocketAddress), ServerPing.builder()
|
||||||
.description(server.getConfiguration().getMotdComponent()).onlinePlayers(server.getPlayerCount())
|
.description(server.getConfiguration().getMotdComponent()).onlinePlayers(server.getPlayerCount())
|
||||||
.maximumPlayers(server.getConfiguration().getShowMaxPlayers()).build())).get();
|
.maximumPlayers(server.getConfiguration().getShowMaxPlayers()).build())).get();
|
||||||
} catch (ExecutionException | InterruptedException e) {
|
} catch (ExecutionException | InterruptedException e) {
|
||||||
|
@ -74,11 +72,15 @@ public class GeyserVelocityPingPassthrough implements IGeyserPingPassthrough {
|
||||||
|
|
||||||
private static class GeyserInboundConnection implements InboundConnection {
|
private static class GeyserInboundConnection implements InboundConnection {
|
||||||
|
|
||||||
private static final InetSocketAddress FAKE_REMOTE = new InetSocketAddress(Inet4Address.getLoopbackAddress(), 69);
|
private final InetSocketAddress remote;
|
||||||
|
|
||||||
|
public GeyserInboundConnection(InetSocketAddress remote) {
|
||||||
|
this.remote = remote;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public InetSocketAddress getRemoteAddress() {
|
public InetSocketAddress getRemoteAddress() {
|
||||||
return FAKE_REMOTE;
|
return this.remote;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -33,9 +33,9 @@ import com.velocitypowered.api.event.proxy.ProxyShutdownEvent;
|
||||||
import com.velocitypowered.api.plugin.Plugin;
|
import com.velocitypowered.api.plugin.Plugin;
|
||||||
import com.velocitypowered.api.proxy.ProxyServer;
|
import com.velocitypowered.api.proxy.ProxyServer;
|
||||||
import lombok.Getter;
|
import lombok.Getter;
|
||||||
|
import org.geysermc.common.PlatformType;
|
||||||
import org.geysermc.connector.GeyserConnector;
|
import org.geysermc.connector.GeyserConnector;
|
||||||
import org.geysermc.connector.bootstrap.GeyserBootstrap;
|
import org.geysermc.connector.bootstrap.GeyserBootstrap;
|
||||||
import org.geysermc.connector.common.PlatformType;
|
|
||||||
import org.geysermc.connector.configuration.GeyserConfiguration;
|
import org.geysermc.connector.configuration.GeyserConfiguration;
|
||||||
import org.geysermc.connector.dump.BootstrapDumpInfo;
|
import org.geysermc.connector.dump.BootstrapDumpInfo;
|
||||||
import org.geysermc.connector.ping.GeyserLegacyPingPassthrough;
|
import org.geysermc.connector.ping.GeyserLegacyPingPassthrough;
|
||||||
|
@ -121,7 +121,7 @@ public class GeyserVelocityPlugin implements GeyserBootstrap {
|
||||||
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("geyser", new GeyserVelocityCommandExecutor(connector));
|
||||||
if (geyserConfig.isLegacyPingPassthrough()) {
|
if (geyserConfig.isLegacyPingPassthrough()) {
|
||||||
this.geyserPingPassthrough = GeyserLegacyPingPassthrough.init(connector);
|
this.geyserPingPassthrough = GeyserLegacyPingPassthrough.init(connector);
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -25,41 +25,48 @@
|
||||||
|
|
||||||
package org.geysermc.platform.velocity.command;
|
package org.geysermc.platform.velocity.command;
|
||||||
|
|
||||||
import com.velocitypowered.api.command.Command;
|
|
||||||
import com.velocitypowered.api.command.CommandSource;
|
import com.velocitypowered.api.command.CommandSource;
|
||||||
|
import com.velocitypowered.api.command.SimpleCommand;
|
||||||
import lombok.AllArgsConstructor;
|
import lombok.AllArgsConstructor;
|
||||||
|
|
||||||
import net.kyori.text.TextComponent;
|
|
||||||
|
|
||||||
import org.geysermc.connector.common.ChatColor;
|
|
||||||
import org.geysermc.connector.GeyserConnector;
|
import org.geysermc.connector.GeyserConnector;
|
||||||
|
import org.geysermc.connector.command.CommandSender;
|
||||||
import org.geysermc.connector.command.GeyserCommand;
|
import org.geysermc.connector.command.GeyserCommand;
|
||||||
|
import org.geysermc.connector.common.ChatColor;
|
||||||
import org.geysermc.connector.utils.LanguageUtils;
|
import org.geysermc.connector.utils.LanguageUtils;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
@AllArgsConstructor
|
@AllArgsConstructor
|
||||||
public class GeyserVelocityCommandExecutor implements Command {
|
public class GeyserVelocityCommandExecutor implements SimpleCommand {
|
||||||
|
|
||||||
private GeyserConnector connector;
|
private final GeyserConnector connector;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void execute(CommandSource source, String[] args) {
|
public void execute(Invocation invocation) {
|
||||||
if (args.length > 0) {
|
if (invocation.arguments().length > 0) {
|
||||||
if (getCommand(args[0]) != null) {
|
if (getCommand(invocation.arguments()[0]) != null) {
|
||||||
if (!source.hasPermission(getCommand(args[0]).getPermission())) {
|
if (!invocation.source().hasPermission(getCommand(invocation.arguments()[0]).getPermission())) {
|
||||||
// Not ideal to use log here but we dont get a session
|
CommandSender sender = new VelocityCommandSender(invocation.source());
|
||||||
source.sendMessage(TextComponent.of(ChatColor.RED + LanguageUtils.getLocaleStringLog("geyser.bootstrap.command.permission_fail")));
|
sender.sendMessage(ChatColor.RED + LanguageUtils.getPlayerLocaleString("geyser.bootstrap.command.permission_fail", sender.getLocale()));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
getCommand(args[0]).execute(new VelocityCommandSender(source), args.length > 1 ? Arrays.copyOfRange(args, 1, args.length) : new String[0]);
|
getCommand(invocation.arguments()[0]).execute(new VelocityCommandSender(invocation.source()), invocation.arguments().length > 1 ? Arrays.copyOfRange(invocation.arguments(), 1, invocation.arguments().length) : new String[0]);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
getCommand("help").execute(new VelocityCommandSender(source), new String[0]);
|
getCommand("help").execute(new VelocityCommandSender(invocation.source()), new String[0]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<String> suggest(Invocation invocation) {
|
||||||
|
if (invocation.arguments().length == 0) {
|
||||||
|
return connector.getCommandManager().getCommandNames();
|
||||||
|
}
|
||||||
|
return new ArrayList<>();
|
||||||
|
}
|
||||||
|
|
||||||
private GeyserCommand getCommand(String label) {
|
private GeyserCommand getCommand(String label) {
|
||||||
return connector.getCommandManager().getCommands().get(label);
|
return connector.getCommandManager().getCommands().get(label);
|
||||||
}
|
}
|
||||||
|
|
|
@ -28,17 +28,21 @@ package org.geysermc.platform.velocity.command;
|
||||||
import com.velocitypowered.api.command.CommandSource;
|
import com.velocitypowered.api.command.CommandSource;
|
||||||
import com.velocitypowered.api.proxy.ConsoleCommandSource;
|
import com.velocitypowered.api.proxy.ConsoleCommandSource;
|
||||||
import com.velocitypowered.api.proxy.Player;
|
import com.velocitypowered.api.proxy.Player;
|
||||||
|
|
||||||
import lombok.AllArgsConstructor;
|
|
||||||
|
|
||||||
import net.kyori.text.TextComponent;
|
import net.kyori.text.TextComponent;
|
||||||
|
|
||||||
import org.geysermc.connector.command.CommandSender;
|
import org.geysermc.connector.command.CommandSender;
|
||||||
|
import org.geysermc.connector.utils.LanguageUtils;
|
||||||
|
|
||||||
|
import java.util.Locale;
|
||||||
|
|
||||||
@AllArgsConstructor
|
|
||||||
public class VelocityCommandSender implements CommandSender {
|
public class VelocityCommandSender implements CommandSender {
|
||||||
|
|
||||||
private CommandSource handle;
|
private final CommandSource handle;
|
||||||
|
|
||||||
|
public VelocityCommandSender(CommandSource handle) {
|
||||||
|
this.handle = handle;
|
||||||
|
// Ensure even Java players' languages are loaded
|
||||||
|
LanguageUtils.loadGeyserLocale(getLocale());
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String getName() {
|
public String getName() {
|
||||||
|
@ -59,4 +63,13 @@ public class VelocityCommandSender implements CommandSender {
|
||||||
public boolean isConsole() {
|
public boolean isConsole() {
|
||||||
return handle instanceof ConsoleCommandSource;
|
return handle instanceof ConsoleCommandSource;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getLocale() {
|
||||||
|
if (handle instanceof Player) {
|
||||||
|
Locale locale = ((Player) handle).getPlayerSettings().getLocale();
|
||||||
|
return LanguageUtils.formatLocale(locale.getLanguage() + "_" + locale.getCountry());
|
||||||
|
}
|
||||||
|
return LanguageUtils.getDefaultLocale();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,11 +6,10 @@
|
||||||
<parent>
|
<parent>
|
||||||
<groupId>org.geysermc</groupId>
|
<groupId>org.geysermc</groupId>
|
||||||
<artifactId>geyser-parent</artifactId>
|
<artifactId>geyser-parent</artifactId>
|
||||||
<version>parent</version>
|
<version>1.2.0-SNAPSHOT</version>
|
||||||
<relativePath>../</relativePath>
|
|
||||||
</parent>
|
</parent>
|
||||||
<artifactId>common</artifactId>
|
<artifactId>common</artifactId>
|
||||||
<version>1.1.0</version>
|
|
||||||
<dependencies>
|
<dependencies>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>com.google.code.gson</groupId>
|
<groupId>com.google.code.gson</groupId>
|
||||||
|
|
|
@ -23,7 +23,7 @@
|
||||||
* @link https://github.com/GeyserMC/Geyser
|
* @link https://github.com/GeyserMC/Geyser
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package org.geysermc.connector.common;
|
package org.geysermc.common;
|
||||||
|
|
||||||
import lombok.AllArgsConstructor;
|
import lombok.AllArgsConstructor;
|
||||||
import lombok.Getter;
|
import lombok.Getter;
|
|
@ -92,7 +92,7 @@ public class CustomFormWindow extends FormWindow {
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setResponse(String data) {
|
public void setResponse(String data) {
|
||||||
if (data == null || data.equalsIgnoreCase("null") || data.isEmpty()) {
|
if (data == null || data.trim().equalsIgnoreCase("null") || data.isEmpty()) {
|
||||||
closed = true;
|
closed = true;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -108,7 +108,7 @@ public class CustomFormWindow extends FormWindow {
|
||||||
|
|
||||||
List<String> componentResponses = new ArrayList<>();
|
List<String> componentResponses = new ArrayList<>();
|
||||||
try {
|
try {
|
||||||
componentResponses = new ObjectMapper().readValue(data, new TypeReference<List<String>>(){});
|
componentResponses = new ObjectMapper().readValue(data.trim(), new TypeReference<List<String>>(){});
|
||||||
} catch (IOException e) { }
|
} catch (IOException e) { }
|
||||||
|
|
||||||
for (String response : componentResponses) {
|
for (String response : componentResponses) {
|
||||||
|
|
|
@ -72,14 +72,14 @@ public class SimpleFormWindow extends FormWindow {
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setResponse(String data) {
|
public void setResponse(String data) {
|
||||||
if (data == null || data.equalsIgnoreCase("null")) {
|
if (data == null || data.trim().equalsIgnoreCase("null")) {
|
||||||
closed = true;
|
closed = true;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
int buttonID;
|
int buttonID;
|
||||||
try {
|
try {
|
||||||
buttonID = Integer.parseInt(data);
|
buttonID = Integer.parseInt(data.trim());
|
||||||
} catch (Exception ex) {
|
} catch (Exception ex) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,16 +6,15 @@
|
||||||
<parent>
|
<parent>
|
||||||
<groupId>org.geysermc</groupId>
|
<groupId>org.geysermc</groupId>
|
||||||
<artifactId>geyser-parent</artifactId>
|
<artifactId>geyser-parent</artifactId>
|
||||||
<version>parent</version>
|
<version>1.2.0-SNAPSHOT</version>
|
||||||
<relativePath>../</relativePath>
|
|
||||||
</parent>
|
</parent>
|
||||||
<artifactId>connector</artifactId>
|
<artifactId>connector</artifactId>
|
||||||
<version>1.1.0</version>
|
|
||||||
<dependencies>
|
<dependencies>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.geysermc</groupId>
|
<groupId>org.geysermc</groupId>
|
||||||
<artifactId>common</artifactId>
|
<artifactId>common</artifactId>
|
||||||
<version>1.1.0</version>
|
<version>1.2.0-SNAPSHOT</version>
|
||||||
<scope>compile</scope>
|
<scope>compile</scope>
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
|
@ -31,17 +30,28 @@
|
||||||
<scope>compile</scope>
|
<scope>compile</scope>
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>com.github.CloudburstMC.Protocol</groupId>
|
<groupId>com.nukkitx.protocol</groupId>
|
||||||
<artifactId>bedrock-v408</artifactId>
|
<artifactId>bedrock-v422</artifactId>
|
||||||
<version>02f46a8700</version>
|
<version>2.6.1-SNAPSHOT</version>
|
||||||
<scope>compile</scope>
|
<scope>compile</scope>
|
||||||
<exclusions>
|
<exclusions>
|
||||||
<exclusion>
|
<exclusion>
|
||||||
<groupId>net.sf.trove4j</groupId>
|
<groupId>net.sf.trove4j</groupId>
|
||||||
<artifactId>trove</artifactId>
|
<artifactId>trove</artifactId>
|
||||||
</exclusion>
|
</exclusion>
|
||||||
|
<!-- Stay on the older version of Network while it's rewritten -->
|
||||||
|
<exclusion>
|
||||||
|
<groupId>com.nukkitx.network</groupId>
|
||||||
|
<artifactId>raknet</artifactId>
|
||||||
|
</exclusion>
|
||||||
</exclusions>
|
</exclusions>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.nukkitx.network</groupId>
|
||||||
|
<artifactId>raknet</artifactId>
|
||||||
|
<version>1.6.20</version>
|
||||||
|
<scope>compile</scope>
|
||||||
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>com.nukkitx.fastutil</groupId>
|
<groupId>com.nukkitx.fastutil</groupId>
|
||||||
<artifactId>fastutil-int-int-maps</artifactId>
|
<artifactId>fastutil-int-int-maps</artifactId>
|
||||||
|
@ -111,13 +121,17 @@
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>com.github.steveice10</groupId>
|
<groupId>com.github.steveice10</groupId>
|
||||||
<artifactId>mcprotocollib</artifactId>
|
<artifactId>mcprotocollib</artifactId>
|
||||||
<version>3a69a0614c</version>
|
<version>26201a4</version>
|
||||||
<scope>compile</scope>
|
<scope>compile</scope>
|
||||||
<exclusions>
|
<exclusions>
|
||||||
<exclusion>
|
<exclusion>
|
||||||
<groupId>io.netty</groupId>
|
<groupId>io.netty</groupId>
|
||||||
<artifactId>netty-all</artifactId>
|
<artifactId>netty-all</artifactId>
|
||||||
</exclusion>
|
</exclusion>
|
||||||
|
<exclusion>
|
||||||
|
<groupId>net.kyori</groupId>
|
||||||
|
<artifactId>adventure-text-serializer-gson</artifactId>
|
||||||
|
</exclusion>
|
||||||
</exclusions>
|
</exclusions>
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
|
@ -137,23 +151,35 @@
|
||||||
<version>2.1.3</version>
|
<version>2.1.3</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>com.github.kyoripowered.adventure</groupId>
|
<groupId>net.kyori</groupId>
|
||||||
<artifactId>adventure-api</artifactId>
|
<artifactId>adventure-api</artifactId>
|
||||||
<version>557865caef</version>
|
<version>4.3.0</version>
|
||||||
<scope>compile</scope>
|
<scope>compile</scope>
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>com.github.kyoripowered.adventure</groupId>
|
<groupId>net.kyori</groupId>
|
||||||
<artifactId>adventure-text-serializer-gson</artifactId>
|
<artifactId>adventure-text-serializer-gson</artifactId>
|
||||||
<version>557865caef</version>
|
<version>4.3.0</version>
|
||||||
<scope>compile</scope>
|
<scope>compile</scope>
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>com.github.kyoripowered.adventure</groupId>
|
<groupId>net.kyori</groupId>
|
||||||
<artifactId>adventure-text-serializer-legacy</artifactId>
|
<artifactId>adventure-text-serializer-legacy</artifactId>
|
||||||
<version>557865caef</version>
|
<version>4.3.0</version>
|
||||||
<scope>compile</scope>
|
<scope>compile</scope>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>net.kyori</groupId>
|
||||||
|
<artifactId>adventure-text-serializer-gson-legacy-impl</artifactId>
|
||||||
|
<version>4.3.0</version>
|
||||||
|
<scope>compile</scope>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>junit</groupId>
|
||||||
|
<artifactId>junit</artifactId>
|
||||||
|
<version>4.13.1</version>
|
||||||
|
<scope>test</scope>
|
||||||
|
</dependency>
|
||||||
</dependencies>
|
</dependencies>
|
||||||
|
|
||||||
<build>
|
<build>
|
||||||
|
@ -210,8 +236,12 @@
|
||||||
</includes>
|
</includes>
|
||||||
<replacements>
|
<replacements>
|
||||||
<replacement>
|
<replacement>
|
||||||
<token>VERSION = ".*"</token>
|
<token>String VERSION = ".*"</token>
|
||||||
<value>VERSION = "${project.version} (git-${git.branch}-${git.commit.id.abbrev})"</value>
|
<value>String VERSION = "${project.version} (" + GIT_VERSION + ")"</value>
|
||||||
|
</replacement>
|
||||||
|
<replacement>
|
||||||
|
<token>String GIT_VERSION = ".*"</token>
|
||||||
|
<value>String GIT_VERSION = "git-${git.branch}-${git.commit.id.abbrev}"</value>
|
||||||
</replacement>
|
</replacement>
|
||||||
</replacements>
|
</replacements>
|
||||||
</configuration>
|
</configuration>
|
||||||
|
@ -229,8 +259,12 @@
|
||||||
</includes>
|
</includes>
|
||||||
<replacements>
|
<replacements>
|
||||||
<replacement>
|
<replacement>
|
||||||
<token>VERSION = ".*"</token>
|
<token>String VERSION = ".*"</token>
|
||||||
<value>VERSION = "DEV"</value>
|
<value>String VERSION = "DEV"</value>
|
||||||
|
</replacement>
|
||||||
|
<replacement>
|
||||||
|
<token>String GIT_VERSION = ".*"</token>
|
||||||
|
<value>String GIT_VERSION = "DEV"</value>
|
||||||
</replacement>
|
</replacement>
|
||||||
</replacements>
|
</replacements>
|
||||||
</configuration>
|
</configuration>
|
||||||
|
@ -252,6 +286,8 @@
|
||||||
<script><![CDATA[
|
<script><![CDATA[
|
||||||
new org.reflections.Reflections("org.geysermc.connector.network.translators")
|
new org.reflections.Reflections("org.geysermc.connector.network.translators")
|
||||||
.save("${project.artifactId}/target/classes/META-INF/reflections/org.geysermc.connector.network.translators-reflections.xml")
|
.save("${project.artifactId}/target/classes/META-INF/reflections/org.geysermc.connector.network.translators-reflections.xml")
|
||||||
|
new org.reflections.Reflections("org.geysermc.connector.network.translators.collision.translators")
|
||||||
|
.save("${project.artifactId}/target/classes/META-INF/reflections/org.geysermc.connector.network.translators.collision.translators-reflections.xml")
|
||||||
new org.reflections.Reflections("org.geysermc.connector.network.translators.item")
|
new org.reflections.Reflections("org.geysermc.connector.network.translators.item")
|
||||||
.save("${project.artifactId}/target/classes/META-INF/reflections/org.geysermc.connector.network.translators.item-reflections.xml")
|
.save("${project.artifactId}/target/classes/META-INF/reflections/org.geysermc.connector.network.translators.item-reflections.xml")
|
||||||
new org.reflections.Reflections("org.geysermc.connector.network.translators.sound")
|
new org.reflections.Reflections("org.geysermc.connector.network.translators.sound")
|
||||||
|
@ -283,6 +319,15 @@
|
||||||
</dependency>
|
</dependency>
|
||||||
</dependencies>
|
</dependencies>
|
||||||
</plugin>
|
</plugin>
|
||||||
|
<plugin>
|
||||||
|
<groupId>org.apache.maven.plugins</groupId>
|
||||||
|
<artifactId>maven-surefire-plugin</artifactId>
|
||||||
|
<version>2.22.0</version>
|
||||||
|
<configuration>
|
||||||
|
<!-- Force the right file encoding during unit testing -->
|
||||||
|
<argLine>-Dfile.encoding=${project.build.sourceEncoding}</argLine>
|
||||||
|
</configuration>
|
||||||
|
</plugin>
|
||||||
</plugins>
|
</plugins>
|
||||||
</build>
|
</build>
|
||||||
</project>
|
</project>
|
||||||
|
|
|
@ -32,10 +32,10 @@ import com.nukkitx.network.raknet.RakNetConstants;
|
||||||
import com.nukkitx.protocol.bedrock.BedrockServer;
|
import com.nukkitx.protocol.bedrock.BedrockServer;
|
||||||
import lombok.Getter;
|
import lombok.Getter;
|
||||||
import lombok.Setter;
|
import lombok.Setter;
|
||||||
|
import org.geysermc.common.PlatformType;
|
||||||
import org.geysermc.connector.bootstrap.GeyserBootstrap;
|
import org.geysermc.connector.bootstrap.GeyserBootstrap;
|
||||||
import org.geysermc.connector.command.CommandManager;
|
import org.geysermc.connector.command.CommandManager;
|
||||||
import org.geysermc.connector.common.AuthType;
|
import org.geysermc.connector.common.AuthType;
|
||||||
import org.geysermc.connector.common.PlatformType;
|
|
||||||
import org.geysermc.connector.configuration.GeyserConfiguration;
|
import org.geysermc.connector.configuration.GeyserConfiguration;
|
||||||
import org.geysermc.connector.metrics.Metrics;
|
import org.geysermc.connector.metrics.Metrics;
|
||||||
import org.geysermc.connector.network.ConnectorServerEventHandler;
|
import org.geysermc.connector.network.ConnectorServerEventHandler;
|
||||||
|
@ -44,6 +44,7 @@ import org.geysermc.connector.network.session.GeyserSession;
|
||||||
import org.geysermc.connector.network.translators.BiomeTranslator;
|
import org.geysermc.connector.network.translators.BiomeTranslator;
|
||||||
import org.geysermc.connector.network.translators.EntityIdentifierRegistry;
|
import org.geysermc.connector.network.translators.EntityIdentifierRegistry;
|
||||||
import org.geysermc.connector.network.translators.PacketTranslatorRegistry;
|
import org.geysermc.connector.network.translators.PacketTranslatorRegistry;
|
||||||
|
import org.geysermc.connector.network.translators.collision.CollisionTranslator;
|
||||||
import org.geysermc.connector.network.translators.effect.EffectRegistry;
|
import org.geysermc.connector.network.translators.effect.EffectRegistry;
|
||||||
import org.geysermc.connector.network.translators.item.ItemRegistry;
|
import org.geysermc.connector.network.translators.item.ItemRegistry;
|
||||||
import org.geysermc.connector.network.translators.item.ItemTranslator;
|
import org.geysermc.connector.network.translators.item.ItemTranslator;
|
||||||
|
@ -54,6 +55,7 @@ import org.geysermc.connector.network.translators.sound.SoundRegistry;
|
||||||
import org.geysermc.connector.network.translators.world.WorldManager;
|
import org.geysermc.connector.network.translators.world.WorldManager;
|
||||||
import org.geysermc.connector.network.translators.world.block.BlockTranslator;
|
import org.geysermc.connector.network.translators.world.block.BlockTranslator;
|
||||||
import org.geysermc.connector.network.translators.world.block.entity.BlockEntityTranslator;
|
import org.geysermc.connector.network.translators.world.block.entity.BlockEntityTranslator;
|
||||||
|
import org.geysermc.connector.network.translators.world.block.entity.SkullBlockEntityTranslator;
|
||||||
import org.geysermc.connector.utils.DimensionUtils;
|
import org.geysermc.connector.utils.DimensionUtils;
|
||||||
import org.geysermc.connector.utils.LanguageUtils;
|
import org.geysermc.connector.utils.LanguageUtils;
|
||||||
import org.geysermc.connector.utils.LocaleUtils;
|
import org.geysermc.connector.utils.LocaleUtils;
|
||||||
|
@ -65,10 +67,7 @@ import java.net.InetAddress;
|
||||||
import java.net.InetSocketAddress;
|
import java.net.InetSocketAddress;
|
||||||
import java.net.UnknownHostException;
|
import java.net.UnknownHostException;
|
||||||
import java.text.DecimalFormat;
|
import java.text.DecimalFormat;
|
||||||
import java.util.ArrayList;
|
import java.util.*;
|
||||||
import java.util.HashMap;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.Map;
|
|
||||||
import java.util.concurrent.CompletableFuture;
|
import java.util.concurrent.CompletableFuture;
|
||||||
import java.util.concurrent.Executors;
|
import java.util.concurrent.Executors;
|
||||||
import java.util.concurrent.ScheduledExecutorService;
|
import java.util.concurrent.ScheduledExecutorService;
|
||||||
|
@ -77,9 +76,14 @@ import java.util.concurrent.TimeUnit;
|
||||||
@Getter
|
@Getter
|
||||||
public class GeyserConnector {
|
public class GeyserConnector {
|
||||||
|
|
||||||
public static final ObjectMapper JSON_MAPPER = new ObjectMapper().enable(JsonParser.Feature.IGNORE_UNDEFINED).enable(JsonParser.Feature.ALLOW_COMMENTS).disable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES);
|
public static final ObjectMapper JSON_MAPPER = new ObjectMapper()
|
||||||
|
.enable(JsonParser.Feature.IGNORE_UNDEFINED)
|
||||||
|
.enable(JsonParser.Feature.ALLOW_COMMENTS)
|
||||||
|
.disable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES)
|
||||||
|
.enable(JsonParser.Feature.ALLOW_UNQUOTED_FIELD_NAMES);
|
||||||
|
|
||||||
public static final String NAME = "Geyser";
|
public static final String NAME = "Geyser";
|
||||||
|
public static final String GIT_VERSION = "DEV"; // A fallback for running in IDEs
|
||||||
public static final String VERSION = "DEV"; // A fallback for running in IDEs
|
public static final String VERSION = "DEV"; // A fallback for running in IDEs
|
||||||
|
|
||||||
private static final String IP_REGEX = "\\b\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}\\b";
|
private static final String IP_REGEX = "\\b\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}\\b";
|
||||||
|
@ -134,6 +138,7 @@ public class GeyserConnector {
|
||||||
EntityIdentifierRegistry.init();
|
EntityIdentifierRegistry.init();
|
||||||
ItemRegistry.init();
|
ItemRegistry.init();
|
||||||
ItemTranslator.init();
|
ItemTranslator.init();
|
||||||
|
CollisionTranslator.init();
|
||||||
LocaleUtils.init();
|
LocaleUtils.init();
|
||||||
PotionMixRegistry.init();
|
PotionMixRegistry.init();
|
||||||
RecipeRegistry.init();
|
RecipeRegistry.init();
|
||||||
|
@ -179,8 +184,8 @@ public class GeyserConnector {
|
||||||
remoteServer = new RemoteServer(config.getRemote().getAddress(), remotePort);
|
remoteServer = new RemoteServer(config.getRemote().getAddress(), remotePort);
|
||||||
authType = AuthType.getByName(config.getRemote().getAuthType());
|
authType = AuthType.getByName(config.getRemote().getAuthType());
|
||||||
|
|
||||||
if (config.isAboveBedrockNetherBuilding())
|
DimensionUtils.changeBedrockNetherId(config.isAboveBedrockNetherBuilding()); // Apply End dimension ID workaround to Nether
|
||||||
DimensionUtils.changeBedrockNetherId(); // Apply End dimension ID workaround to Nether
|
SkullBlockEntityTranslator.ALLOW_CUSTOM_SKULLS = config.isAllowCustomSkulls();
|
||||||
|
|
||||||
// https://github.com/GeyserMC/Geyser/issues/957
|
// https://github.com/GeyserMC/Geyser/issues/957
|
||||||
RakNetConstants.MAXIMUM_MTU_SIZE = (short) config.getMtu();
|
RakNetConstants.MAXIMUM_MTU_SIZE = (short) config.getMtu();
|
||||||
|
@ -199,7 +204,6 @@ public class GeyserConnector {
|
||||||
|
|
||||||
if (config.getMetrics().isEnabled()) {
|
if (config.getMetrics().isEnabled()) {
|
||||||
metrics = new Metrics(this, "GeyserMC", config.getMetrics().getUniqueId(), false, java.util.logging.Logger.getLogger(""));
|
metrics = new Metrics(this, "GeyserMC", config.getMetrics().getUniqueId(), false, java.util.logging.Logger.getLogger(""));
|
||||||
metrics.addCustomChart(new Metrics.SingleLineChart("servers", () -> 1));
|
|
||||||
metrics.addCustomChart(new Metrics.SingleLineChart("players", players::size));
|
metrics.addCustomChart(new Metrics.SingleLineChart("players", players::size));
|
||||||
// Prevent unwanted words best we can
|
// Prevent unwanted words best we can
|
||||||
metrics.addCustomChart(new Metrics.SimplePie("authMode", () -> AuthType.getByName(config.getRemote().getAuthType()).toString().toLowerCase()));
|
metrics.addCustomChart(new Metrics.SimplePie("authMode", () -> AuthType.getByName(config.getRemote().getAuthType()).toString().toLowerCase()));
|
||||||
|
@ -271,7 +275,7 @@ public class GeyserConnector {
|
||||||
// Make a copy to prevent ConcurrentModificationException
|
// Make a copy to prevent ConcurrentModificationException
|
||||||
final List<GeyserSession> tmpPlayers = new ArrayList<>(players);
|
final List<GeyserSession> tmpPlayers = new ArrayList<>(players);
|
||||||
for (GeyserSession playerSession : tmpPlayers) {
|
for (GeyserSession playerSession : tmpPlayers) {
|
||||||
playerSession.disconnect(LanguageUtils.getPlayerLocaleString("geyser.core.shutdown.kick.message", playerSession.getClientData().getLanguageCode()));
|
playerSession.disconnect(LanguageUtils.getPlayerLocaleString("geyser.core.shutdown.kick.message", playerSession.getLocale()));
|
||||||
}
|
}
|
||||||
|
|
||||||
CompletableFuture<Void> future = CompletableFuture.runAsync(new Runnable() {
|
CompletableFuture<Void> future = CompletableFuture.runAsync(new Runnable() {
|
||||||
|
@ -319,6 +323,38 @@ public class GeyserConnector {
|
||||||
players.remove(player);
|
players.remove(player);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets a player by their current UUID
|
||||||
|
*
|
||||||
|
* @param uuid the uuid
|
||||||
|
* @return the player or <code>null</code> if there is no player online with this UUID
|
||||||
|
*/
|
||||||
|
public GeyserSession getPlayerByUuid(UUID uuid) {
|
||||||
|
for (GeyserSession session : players) {
|
||||||
|
if (session.getPlayerEntity().getUuid().equals(uuid)) {
|
||||||
|
return session;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets a player by their Xbox user identifier
|
||||||
|
*
|
||||||
|
* @param xuid the Xbox user identifier
|
||||||
|
* @return the player or <code>null</code> if there is no player online with this xuid
|
||||||
|
*/
|
||||||
|
public GeyserSession getPlayerByXuid(String xuid) {
|
||||||
|
for (GeyserSession session : players) {
|
||||||
|
if (session.getAuthData() != null && session.getAuthData().getXboxUUID().equals(xuid)) {
|
||||||
|
return session;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
public static GeyserConnector start(PlatformType platformType, GeyserBootstrap bootstrap) {
|
public static GeyserConnector start(PlatformType platformType, GeyserBootstrap bootstrap) {
|
||||||
return new GeyserConnector(platformType, bootstrap);
|
return new GeyserConnector(platformType, bootstrap);
|
||||||
}
|
}
|
||||||
|
|
|
@ -31,27 +31,27 @@ import org.geysermc.connector.GeyserConnector;
|
||||||
import org.geysermc.connector.command.defaults.*;
|
import org.geysermc.connector.command.defaults.*;
|
||||||
import org.geysermc.connector.utils.LanguageUtils;
|
import org.geysermc.connector.utils.LanguageUtils;
|
||||||
|
|
||||||
import java.util.Collections;
|
import java.util.*;
|
||||||
import java.util.HashMap;
|
|
||||||
import java.util.Map;
|
|
||||||
|
|
||||||
public abstract class CommandManager {
|
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<>());
|
||||||
|
|
||||||
private GeyserConnector connector;
|
private final GeyserConnector connector;
|
||||||
|
|
||||||
public CommandManager(GeyserConnector connector) {
|
public CommandManager(GeyserConnector connector) {
|
||||||
this.connector = connector;
|
this.connector = connector;
|
||||||
|
|
||||||
registerCommand(new HelpCommand(connector, "help", LanguageUtils.getLocaleStringLog("geyser.commands.help.desc"), "geyser.command.help"));
|
registerCommand(new HelpCommand(connector, "help", "geyser.commands.help.desc", "geyser.command.help"));
|
||||||
registerCommand(new ListCommand(connector, "list", LanguageUtils.getLocaleStringLog("geyser.commands.list.desc"), "geyser.command.list"));
|
registerCommand(new ListCommand(connector, "list", "geyser.commands.list.desc", "geyser.command.list"));
|
||||||
registerCommand(new ReloadCommand(connector, "reload", LanguageUtils.getLocaleStringLog("geyser.commands.reload.desc"), "geyser.command.reload"));
|
registerCommand(new ReloadCommand(connector, "reload", "geyser.commands.reload.desc", "geyser.command.reload"));
|
||||||
registerCommand(new StopCommand(connector, "stop", LanguageUtils.getLocaleStringLog("geyser.commands.stop.desc"), "geyser.command.stop"));
|
registerCommand(new StopCommand(connector, "stop", "geyser.commands.stop.desc", "geyser.command.stop"));
|
||||||
registerCommand(new OffhandCommand(connector, "offhand", LanguageUtils.getLocaleStringLog("geyser.commands.offhand.desc"), "geyser.command.offhand"));
|
registerCommand(new OffhandCommand(connector, "offhand", "geyser.commands.offhand.desc", "geyser.command.offhand"));
|
||||||
registerCommand(new DumpCommand(connector, "dump", LanguageUtils.getLocaleStringLog("geyser.commands.dump.desc"), "geyser.command.dump"));
|
registerCommand(new DumpCommand(connector, "dump", "geyser.commands.dump.desc", "geyser.command.dump"));
|
||||||
registerCommand(new VersionCommand(connector, "version", LanguageUtils.getLocaleStringLog("geyser.commands.version.desc"), "geyser.command.version"));
|
registerCommand(new VersionCommand(connector, "version", "geyser.commands.version.desc", "geyser.command.version"));
|
||||||
|
registerCommand(new SettingsCommand(connector, "settings", "geyser.commands.settings.desc", "geyser.command.settings"));
|
||||||
|
registerCommand(new StatisticsCommand(connector, "statistics", "geyser.commands.statistics.desc", "geyser.command.statistics"));
|
||||||
}
|
}
|
||||||
|
|
||||||
public void registerCommand(GeyserCommand command) {
|
public void registerCommand(GeyserCommand command) {
|
||||||
|
@ -91,6 +91,13 @@ public abstract class CommandManager {
|
||||||
cmd.execute(sender, args);
|
cmd.execute(sender, args);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return a list of all subcommands under {@code /geyser}.
|
||||||
|
*/
|
||||||
|
public List<String> getCommandNames() {
|
||||||
|
return Arrays.asList(connector.getCommandManager().getCommands().keySet().toArray(new String[0]));
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the description of the given command
|
* Returns the description of the given command
|
||||||
*
|
*
|
||||||
|
|
|
@ -25,6 +25,12 @@
|
||||||
|
|
||||||
package org.geysermc.connector.command;
|
package org.geysermc.connector.command;
|
||||||
|
|
||||||
|
import org.geysermc.connector.utils.LanguageUtils;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Implemented on top of any class that can send a command.
|
||||||
|
* For example, it wraps around Spigot's CommandSender class.
|
||||||
|
*/
|
||||||
public interface CommandSender {
|
public interface CommandSender {
|
||||||
|
|
||||||
String getName();
|
String getName();
|
||||||
|
@ -37,5 +43,17 @@ public interface CommandSender {
|
||||||
|
|
||||||
void sendMessage(String message);
|
void sendMessage(String message);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return true if the specified sender is from the console.
|
||||||
|
*/
|
||||||
boolean isConsole();
|
boolean isConsole();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the locale of the command sender. Defaults to the default locale at {@link LanguageUtils#getDefaultLocale()}.
|
||||||
|
*
|
||||||
|
* @return the locale of the command sender.
|
||||||
|
*/
|
||||||
|
default String getLocale() {
|
||||||
|
return LanguageUtils.getDefaultLocale();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -30,6 +30,7 @@ import lombok.RequiredArgsConstructor;
|
||||||
import lombok.Setter;
|
import lombok.Setter;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
import java.util.Collections;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
@Getter
|
@Getter
|
||||||
|
@ -37,6 +38,9 @@ import java.util.List;
|
||||||
public abstract class GeyserCommand {
|
public abstract class GeyserCommand {
|
||||||
|
|
||||||
protected final String name;
|
protected final String name;
|
||||||
|
/**
|
||||||
|
* The description of the command - will attempt to be translated.
|
||||||
|
*/
|
||||||
protected final String description;
|
protected final String description;
|
||||||
protected final String permission;
|
protected final String permission;
|
||||||
|
|
||||||
|
@ -44,4 +48,31 @@ public abstract class GeyserCommand {
|
||||||
private List<String> aliases = new ArrayList<>();
|
private List<String> aliases = new ArrayList<>();
|
||||||
|
|
||||||
public abstract void execute(CommandSender sender, String[] args);
|
public abstract void execute(CommandSender sender, String[] args);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* If false, hides the command from being shown on the Geyser Standalone GUI.
|
||||||
|
*
|
||||||
|
* @return true if the command can be run on the server console
|
||||||
|
*/
|
||||||
|
public boolean isExecutableOnConsole() {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Used in the GUI to know what subcommands can be run
|
||||||
|
*
|
||||||
|
* @return a list of all possible subcommands, or empty if none.
|
||||||
|
*/
|
||||||
|
public List<String> getSubCommands() {
|
||||||
|
return Collections.emptyList();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Shortcut to {@link #getSubCommands()}{@code .isEmpty()}.
|
||||||
|
*
|
||||||
|
* @return true if there are subcommand present for this command.
|
||||||
|
*/
|
||||||
|
public boolean hasSubCommands() {
|
||||||
|
return !getSubCommands().isEmpty();
|
||||||
|
}
|
||||||
}
|
}
|
|
@ -27,12 +27,10 @@ package org.geysermc.connector.command.defaults;
|
||||||
|
|
||||||
import com.fasterxml.jackson.databind.JsonNode;
|
import com.fasterxml.jackson.databind.JsonNode;
|
||||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||||
import com.fasterxml.jackson.databind.ser.impl.SimpleBeanPropertyFilter;
|
|
||||||
import com.fasterxml.jackson.databind.ser.impl.SimpleFilterProvider;
|
|
||||||
import org.geysermc.connector.common.ChatColor;
|
|
||||||
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.command.GeyserCommand;
|
import org.geysermc.connector.command.GeyserCommand;
|
||||||
|
import org.geysermc.connector.common.ChatColor;
|
||||||
import org.geysermc.connector.common.serializer.AsteriskSerializer;
|
import org.geysermc.connector.common.serializer.AsteriskSerializer;
|
||||||
import org.geysermc.connector.dump.DumpInfo;
|
import org.geysermc.connector.dump.DumpInfo;
|
||||||
import org.geysermc.connector.utils.LanguageUtils;
|
import org.geysermc.connector.utils.LanguageUtils;
|
||||||
|
@ -40,6 +38,8 @@ import org.geysermc.connector.utils.WebUtils;
|
||||||
|
|
||||||
import java.io.FileOutputStream;
|
import java.io.FileOutputStream;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
public class DumpCommand extends GeyserCommand {
|
public class DumpCommand extends GeyserCommand {
|
||||||
|
|
||||||
|
@ -73,7 +73,7 @@ public class DumpCommand extends GeyserCommand {
|
||||||
|
|
||||||
AsteriskSerializer.showSensitive = showSensitive;
|
AsteriskSerializer.showSensitive = showSensitive;
|
||||||
|
|
||||||
sender.sendMessage(LanguageUtils.getLocaleStringLog("geyser.commands.dump.collecting"));
|
sender.sendMessage(LanguageUtils.getPlayerLocaleString("geyser.commands.dump.collecting", sender.getLocale()));
|
||||||
String dumpData = "";
|
String dumpData = "";
|
||||||
try {
|
try {
|
||||||
if (offlineDump) {
|
if (offlineDump) {
|
||||||
|
@ -82,7 +82,7 @@ public class DumpCommand extends GeyserCommand {
|
||||||
dumpData = MAPPER.writeValueAsString(new DumpInfo());
|
dumpData = MAPPER.writeValueAsString(new DumpInfo());
|
||||||
}
|
}
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
sender.sendMessage(ChatColor.RED + LanguageUtils.getLocaleStringLog("geyser.commands.dump.collect_error"));
|
sender.sendMessage(ChatColor.RED + LanguageUtils.getPlayerLocaleString("geyser.commands.dump.collect_error", sender.getLocale()));
|
||||||
connector.getLogger().error(LanguageUtils.getLocaleStringLog("geyser.commands.dump.collect_error_short"), e);
|
connector.getLogger().error(LanguageUtils.getLocaleStringLog("geyser.commands.dump.collect_error_short"), e);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -90,21 +90,21 @@ public class DumpCommand extends GeyserCommand {
|
||||||
String uploadedDumpUrl = "";
|
String uploadedDumpUrl = "";
|
||||||
|
|
||||||
if (offlineDump) {
|
if (offlineDump) {
|
||||||
sender.sendMessage(LanguageUtils.getLocaleStringLog("geyser.commands.dump.writing"));
|
sender.sendMessage(LanguageUtils.getPlayerLocaleString("geyser.commands.dump.writing", sender.getLocale()));
|
||||||
|
|
||||||
try {
|
try {
|
||||||
FileOutputStream outputStream = new FileOutputStream(GeyserConnector.getInstance().getBootstrap().getConfigFolder().resolve("dump.json").toFile());
|
FileOutputStream outputStream = new FileOutputStream(GeyserConnector.getInstance().getBootstrap().getConfigFolder().resolve("dump.json").toFile());
|
||||||
outputStream.write(dumpData.getBytes());
|
outputStream.write(dumpData.getBytes());
|
||||||
outputStream.close();
|
outputStream.close();
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
sender.sendMessage(ChatColor.RED + LanguageUtils.getLocaleStringLog("geyser.commands.dump.write_error"));
|
sender.sendMessage(ChatColor.RED + LanguageUtils.getPlayerLocaleString("geyser.commands.dump.write_error", sender.getLocale()));
|
||||||
connector.getLogger().error(LanguageUtils.getLocaleStringLog("geyser.commands.dump.write_error_short"), e);
|
connector.getLogger().error(LanguageUtils.getLocaleStringLog("geyser.commands.dump.write_error_short"), e);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
uploadedDumpUrl = "dump.json";
|
uploadedDumpUrl = "dump.json";
|
||||||
} else {
|
} else {
|
||||||
sender.sendMessage(LanguageUtils.getLocaleStringLog("geyser.commands.dump.uploading"));
|
sender.sendMessage(LanguageUtils.getPlayerLocaleString("geyser.commands.dump.uploading", sender.getLocale()));
|
||||||
|
|
||||||
String response;
|
String response;
|
||||||
JsonNode responseNode;
|
JsonNode responseNode;
|
||||||
|
@ -112,22 +112,27 @@ public class DumpCommand extends GeyserCommand {
|
||||||
response = WebUtils.post(DUMP_URL + "documents", dumpData);
|
response = WebUtils.post(DUMP_URL + "documents", dumpData);
|
||||||
responseNode = MAPPER.readTree(response);
|
responseNode = MAPPER.readTree(response);
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
sender.sendMessage(ChatColor.RED + LanguageUtils.getLocaleStringLog("geyser.commands.dump.upload_error"));
|
sender.sendMessage(ChatColor.RED + LanguageUtils.getPlayerLocaleString("geyser.commands.dump.upload_error", sender.getLocale()));
|
||||||
connector.getLogger().error(LanguageUtils.getLocaleStringLog("geyser.commands.dump.upload_error_short"), e);
|
connector.getLogger().error(LanguageUtils.getLocaleStringLog("geyser.commands.dump.upload_error_short"), e);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!responseNode.has("key")) {
|
if (!responseNode.has("key")) {
|
||||||
sender.sendMessage(ChatColor.RED + LanguageUtils.getLocaleStringLog("geyser.commands.dump.upload_error_short") + ": " + (responseNode.has("message") ? responseNode.get("message").asText() : response));
|
sender.sendMessage(ChatColor.RED + LanguageUtils.getPlayerLocaleString("geyser.commands.dump.upload_error_short", sender.getLocale()) + ": " + (responseNode.has("message") ? responseNode.get("message").asText() : response));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
uploadedDumpUrl = DUMP_URL + responseNode.get("key").asText();
|
uploadedDumpUrl = DUMP_URL + responseNode.get("key").asText();
|
||||||
}
|
}
|
||||||
|
|
||||||
sender.sendMessage(LanguageUtils.getLocaleStringLog("geyser.commands.dump.message") + " " + ChatColor.DARK_AQUA + uploadedDumpUrl);
|
sender.sendMessage(LanguageUtils.getPlayerLocaleString("geyser.commands.dump.message", sender.getLocale()) + " " + ChatColor.DARK_AQUA + uploadedDumpUrl);
|
||||||
if (!sender.isConsole()) {
|
if (!sender.isConsole()) {
|
||||||
connector.getLogger().info(LanguageUtils.getLocaleStringLog("geyser.commands.dump.created", sender.getName(), uploadedDumpUrl));
|
connector.getLogger().info(LanguageUtils.getLocaleStringLog("geyser.commands.dump.created", sender.getName(), uploadedDumpUrl));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<String> getSubCommands() {
|
||||||
|
return Arrays.asList("offline", "full");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -25,11 +25,10 @@
|
||||||
|
|
||||||
package org.geysermc.connector.command.defaults;
|
package org.geysermc.connector.command.defaults;
|
||||||
|
|
||||||
import org.geysermc.connector.common.ChatColor;
|
|
||||||
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.command.GeyserCommand;
|
import org.geysermc.connector.command.GeyserCommand;
|
||||||
import org.geysermc.connector.network.session.GeyserSession;
|
import org.geysermc.connector.common.ChatColor;
|
||||||
import org.geysermc.connector.utils.LanguageUtils;
|
import org.geysermc.connector.utils.LanguageUtils;
|
||||||
|
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
|
@ -52,17 +51,12 @@ public class HelpCommand extends GeyserCommand {
|
||||||
public void execute(CommandSender sender, String[] args) {
|
public void execute(CommandSender sender, String[] args) {
|
||||||
int page = 1;
|
int page = 1;
|
||||||
int maxPage = 1;
|
int maxPage = 1;
|
||||||
String header = "";
|
String header = LanguageUtils.getPlayerLocaleString("geyser.commands.help.header", sender.getLocale(), page, maxPage);
|
||||||
|
|
||||||
if (sender instanceof GeyserSession) {
|
|
||||||
header = LanguageUtils.getPlayerLocaleString("geyser.commands.help.header", ((GeyserSession) sender).getClientData().getLanguageCode(), page, maxPage);
|
|
||||||
} else {
|
|
||||||
header = LanguageUtils.getLocaleStringLog("geyser.commands.help.header", page, maxPage);
|
|
||||||
}
|
|
||||||
|
|
||||||
sender.sendMessage(header);
|
sender.sendMessage(header);
|
||||||
Map<String, GeyserCommand> cmds = connector.getCommandManager().getCommands();
|
Map<String, GeyserCommand> cmds = connector.getCommandManager().getCommands();
|
||||||
List<String> commands = connector.getCommandManager().getCommands().keySet().stream().sorted().collect(Collectors.toList());
|
List<String> commands = connector.getCommandManager().getCommands().keySet().stream().sorted().collect(Collectors.toList());
|
||||||
commands.forEach(cmd -> sender.sendMessage(ChatColor.YELLOW + "/geyser " + cmd + ChatColor.WHITE + ": " + cmds.get(cmd).getDescription()));
|
commands.forEach(cmd -> sender.sendMessage(ChatColor.YELLOW + "/geyser " + cmd + ChatColor.WHITE + ": " +
|
||||||
|
LanguageUtils.getPlayerLocaleString(cmds.get(cmd).getDescription(), sender.getLocale())));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -35,7 +35,7 @@ import java.util.stream.Collectors;
|
||||||
|
|
||||||
public class ListCommand extends GeyserCommand {
|
public class ListCommand extends GeyserCommand {
|
||||||
|
|
||||||
private GeyserConnector connector;
|
private final GeyserConnector connector;
|
||||||
|
|
||||||
public ListCommand(GeyserConnector connector, String name, String description, String permission) {
|
public ListCommand(GeyserConnector connector, String name, String description, String permission) {
|
||||||
super(name, description, permission);
|
super(name, description, permission);
|
||||||
|
@ -46,11 +46,9 @@ public class ListCommand extends GeyserCommand {
|
||||||
@Override
|
@Override
|
||||||
public void execute(CommandSender sender, String[] args) {
|
public void execute(CommandSender sender, String[] args) {
|
||||||
String message = "";
|
String message = "";
|
||||||
if (sender instanceof GeyserSession) {
|
message = LanguageUtils.getPlayerLocaleString("geyser.commands.list.message", sender.getLocale(),
|
||||||
message = LanguageUtils.getPlayerLocaleString("geyser.commands.list.message", ((GeyserSession) sender).getClientData().getLanguageCode(), connector.getPlayers().size(), connector.getPlayers().stream().map(GeyserSession::getName).collect(Collectors.joining(" ")));
|
connector.getPlayers().size(),
|
||||||
} else {
|
connector.getPlayers().stream().map(GeyserSession::getName).collect(Collectors.joining(" ")));
|
||||||
message = LanguageUtils.getLocaleStringLog("geyser.commands.list.message", connector.getPlayers().size(), connector.getPlayers().stream().map(GeyserSession::getName).collect(Collectors.joining(" ")));
|
|
||||||
}
|
|
||||||
|
|
||||||
sender.sendMessage(message);
|
sender.sendMessage(message);
|
||||||
}
|
}
|
||||||
|
|
|
@ -36,7 +36,7 @@ import org.geysermc.connector.network.session.GeyserSession;
|
||||||
|
|
||||||
public class OffhandCommand extends GeyserCommand {
|
public class OffhandCommand extends GeyserCommand {
|
||||||
|
|
||||||
private GeyserConnector connector;
|
private final GeyserConnector connector;
|
||||||
|
|
||||||
public OffhandCommand(GeyserConnector connector, String name, String description, String permission) {
|
public OffhandCommand(GeyserConnector connector, String name, String description, String permission) {
|
||||||
super(name, description, permission);
|
super(name, description, permission);
|
||||||
|
@ -58,7 +58,7 @@ public class OffhandCommand extends GeyserCommand {
|
||||||
session.sendDownstreamPacket(releaseItemPacket);
|
session.sendDownstreamPacket(releaseItemPacket);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
// Needed for Bukkit - sender is not an instance of GeyserSession
|
// Needed for Spigot - sender is not an instance of GeyserSession
|
||||||
for (GeyserSession session : connector.getPlayers()) {
|
for (GeyserSession session : connector.getPlayers()) {
|
||||||
if (sender.getName().equals(session.getPlayerEntity().getUsername())) {
|
if (sender.getName().equals(session.getPlayerEntity().getUsername())) {
|
||||||
ClientPlayerActionPacket releaseItemPacket = new ClientPlayerActionPacket(PlayerAction.SWAP_HANDS, new Position(0,0,0),
|
ClientPlayerActionPacket releaseItemPacket = new ClientPlayerActionPacket(PlayerAction.SWAP_HANDS, new Position(0,0,0),
|
||||||
|
@ -68,4 +68,9 @@ public class OffhandCommand extends GeyserCommand {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isExecutableOnConsole() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -25,7 +25,7 @@
|
||||||
|
|
||||||
package org.geysermc.connector.command.defaults;
|
package org.geysermc.connector.command.defaults;
|
||||||
|
|
||||||
import org.geysermc.connector.common.PlatformType;
|
import org.geysermc.common.PlatformType;
|
||||||
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.command.GeyserCommand;
|
import org.geysermc.connector.command.GeyserCommand;
|
||||||
|
@ -47,17 +47,12 @@ public class ReloadCommand extends GeyserCommand {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
String message = "";
|
String message = LanguageUtils.getPlayerLocaleString("geyser.commands.reload.message", sender.getLocale());
|
||||||
if (sender instanceof GeyserSession) {
|
|
||||||
message = LanguageUtils.getPlayerLocaleString("geyser.commands.reload.message", ((GeyserSession) sender).getClientData().getLanguageCode());
|
|
||||||
} else {
|
|
||||||
message = LanguageUtils.getLocaleStringLog("geyser.commands.reload.message");
|
|
||||||
}
|
|
||||||
|
|
||||||
sender.sendMessage(message);
|
sender.sendMessage(message);
|
||||||
|
|
||||||
for (GeyserSession session : connector.getPlayers()) {
|
for (GeyserSession session : connector.getPlayers()) {
|
||||||
session.disconnect(LanguageUtils.getPlayerLocaleString("geyser.commands.reload.kick", session.getClientData().getLanguageCode()));
|
session.disconnect(LanguageUtils.getPlayerLocaleString("geyser.commands.reload.kick", session.getLocale()));
|
||||||
}
|
}
|
||||||
connector.reload();
|
connector.reload();
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,68 @@
|
||||||
|
/*
|
||||||
|
* 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.command.defaults;
|
||||||
|
|
||||||
|
import org.geysermc.connector.GeyserConnector;
|
||||||
|
import org.geysermc.connector.command.CommandSender;
|
||||||
|
import org.geysermc.connector.command.GeyserCommand;
|
||||||
|
import org.geysermc.connector.network.session.GeyserSession;
|
||||||
|
import org.geysermc.connector.utils.SettingsUtils;
|
||||||
|
|
||||||
|
public class SettingsCommand extends GeyserCommand {
|
||||||
|
|
||||||
|
private final GeyserConnector connector;
|
||||||
|
|
||||||
|
public SettingsCommand(GeyserConnector connector, String name, String description, String permission) {
|
||||||
|
super(name, description, permission);
|
||||||
|
|
||||||
|
this.connector = connector;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void execute(CommandSender sender, String[] args) {
|
||||||
|
// Make sure the sender is a Bedrock edition client
|
||||||
|
GeyserSession session = null;
|
||||||
|
if (sender instanceof GeyserSession) {
|
||||||
|
session = (GeyserSession) sender;
|
||||||
|
} else {
|
||||||
|
// Needed for Spigot - sender is not an instance of GeyserSession
|
||||||
|
for (GeyserSession otherSession : connector.getPlayers()) {
|
||||||
|
if (sender.getName().equals(otherSession.getPlayerEntity().getUsername())) {
|
||||||
|
session = otherSession;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (session == null) return;
|
||||||
|
SettingsUtils.buildForm(session);
|
||||||
|
session.sendForm(session.getSettingsForm(), SettingsUtils.SETTINGS_FORM_ID);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isExecutableOnConsole() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
|
@ -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.connector.command.defaults;
|
||||||
|
|
||||||
|
import com.github.steveice10.mc.protocol.data.game.ClientRequest;
|
||||||
|
import com.github.steveice10.mc.protocol.packet.ingame.client.ClientRequestPacket;
|
||||||
|
import org.geysermc.connector.GeyserConnector;
|
||||||
|
import org.geysermc.connector.command.CommandSender;
|
||||||
|
import org.geysermc.connector.command.GeyserCommand;
|
||||||
|
import org.geysermc.connector.network.session.GeyserSession;
|
||||||
|
|
||||||
|
public class StatisticsCommand extends GeyserCommand {
|
||||||
|
|
||||||
|
private final GeyserConnector connector;
|
||||||
|
|
||||||
|
public StatisticsCommand(GeyserConnector connector, String name, String description, String permission) {
|
||||||
|
super(name, description, permission);
|
||||||
|
|
||||||
|
this.connector = connector;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void execute(CommandSender sender, String[] args) {
|
||||||
|
if (sender.isConsole()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Make sure the sender is a Bedrock edition client
|
||||||
|
GeyserSession session = null;
|
||||||
|
if (sender instanceof GeyserSession) {
|
||||||
|
session = (GeyserSession) sender;
|
||||||
|
} else {
|
||||||
|
// Needed for Spigot - sender is not an instance of GeyserSession
|
||||||
|
for (GeyserSession otherSession : connector.getPlayers()) {
|
||||||
|
if (sender.getName().equals(otherSession.getPlayerEntity().getUsername())) {
|
||||||
|
session = otherSession;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (session == null) return;
|
||||||
|
session.setWaitingForStatistics(true);
|
||||||
|
ClientRequestPacket clientRequestPacket = new ClientRequestPacket(ClientRequest.STATS);
|
||||||
|
session.sendDownstreamPacket(clientRequestPacket);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isExecutableOnConsole() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
|
@ -25,7 +25,7 @@
|
||||||
|
|
||||||
package org.geysermc.connector.command.defaults;
|
package org.geysermc.connector.command.defaults;
|
||||||
|
|
||||||
import org.geysermc.connector.common.PlatformType;
|
import org.geysermc.common.PlatformType;
|
||||||
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.command.GeyserCommand;
|
import org.geysermc.connector.command.GeyserCommand;
|
||||||
|
|
|
@ -61,12 +61,12 @@ public class VersionCommand extends GeyserCommand {
|
||||||
bedrockVersions = BedrockProtocol.DEFAULT_BEDROCK_CODEC.getMinecraftVersion();
|
bedrockVersions = BedrockProtocol.DEFAULT_BEDROCK_CODEC.getMinecraftVersion();
|
||||||
}
|
}
|
||||||
|
|
||||||
sender.sendMessage(LanguageUtils.getLocaleStringLog("geyser.commands.version.version", GeyserConnector.NAME, GeyserConnector.VERSION, MinecraftConstants.GAME_VERSION, bedrockVersions));
|
sender.sendMessage(LanguageUtils.getPlayerLocaleString("geyser.commands.version.version", sender.getLocale(), GeyserConnector.NAME, GeyserConnector.VERSION, MinecraftConstants.GAME_VERSION, bedrockVersions));
|
||||||
|
|
||||||
// Disable update checking in dev mode
|
// Disable update checking in dev mode
|
||||||
//noinspection ConstantConditions - changes in production
|
//noinspection ConstantConditions - changes in production
|
||||||
if (!GeyserConnector.VERSION.equals("DEV")) {
|
if (!GeyserConnector.VERSION.equals("DEV")) {
|
||||||
sender.sendMessage(LanguageUtils.getLocaleStringLog("geyser.commands.version.checking"));
|
sender.sendMessage(LanguageUtils.getPlayerLocaleString("geyser.commands.version.checking", sender.getLocale()));
|
||||||
try {
|
try {
|
||||||
Properties gitProp = new Properties();
|
Properties gitProp = new Properties();
|
||||||
gitProp.load(FileUtils.getResource("git.properties"));
|
gitProp.load(FileUtils.getResource("git.properties"));
|
||||||
|
@ -76,16 +76,16 @@ public class VersionCommand extends GeyserCommand {
|
||||||
int latestBuildNum = Integer.parseInt(buildXML.replaceAll("<(\\\\)?(/)?buildNumber>", "").trim());
|
int latestBuildNum = Integer.parseInt(buildXML.replaceAll("<(\\\\)?(/)?buildNumber>", "").trim());
|
||||||
int buildNum = Integer.parseInt(gitProp.getProperty("git.build.number"));
|
int buildNum = Integer.parseInt(gitProp.getProperty("git.build.number"));
|
||||||
if (latestBuildNum == buildNum) {
|
if (latestBuildNum == buildNum) {
|
||||||
sender.sendMessage(LanguageUtils.getLocaleStringLog("geyser.commands.version.no_updates"));
|
sender.sendMessage(LanguageUtils.getPlayerLocaleString("geyser.commands.version.no_updates", sender.getLocale()));
|
||||||
} else {
|
} else {
|
||||||
sender.sendMessage(LanguageUtils.getLocaleStringLog("geyser.commands.version.outdated", (latestBuildNum - buildNum), "http://ci.geysermc.org/"));
|
sender.sendMessage(LanguageUtils.getPlayerLocaleString("geyser.commands.version.outdated", sender.getLocale(), (latestBuildNum - buildNum), "https://ci.geysermc.org/"));
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
throw new AssertionError("buildNumber missing");
|
throw new AssertionError("buildNumber missing");
|
||||||
}
|
}
|
||||||
} catch (IOException | AssertionError | NumberFormatException e) {
|
} catch (IOException | AssertionError | NumberFormatException e) {
|
||||||
GeyserConnector.getInstance().getLogger().error(LanguageUtils.getLocaleStringLog("geyser.commands.version.failed"), e);
|
GeyserConnector.getInstance().getLogger().error(LanguageUtils.getLocaleStringLog("geyser.commands.version.failed"), e);
|
||||||
sender.sendMessage(ChatColor.RED + LanguageUtils.getLocaleStringLog("geyser.commands.version.failed"));
|
sender.sendMessage(ChatColor.RED + LanguageUtils.getPlayerLocaleString("geyser.commands.version.failed", sender.getLocale()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -71,6 +71,8 @@ public interface GeyserConfiguration {
|
||||||
|
|
||||||
boolean isShowCooldown();
|
boolean isShowCooldown();
|
||||||
|
|
||||||
|
boolean isShowCoordinates();
|
||||||
|
|
||||||
String getDefaultLocale();
|
String getDefaultLocale();
|
||||||
|
|
||||||
Path getFloodgateKeyPath();
|
Path getFloodgateKeyPath();
|
||||||
|
@ -81,8 +83,12 @@ public interface GeyserConfiguration {
|
||||||
|
|
||||||
boolean isForceResourcePacks();
|
boolean isForceResourcePacks();
|
||||||
|
|
||||||
|
boolean isXboxAchievementsEnabled();
|
||||||
|
|
||||||
int getCacheImages();
|
int getCacheImages();
|
||||||
|
|
||||||
|
boolean isAllowCustomSkulls();
|
||||||
|
|
||||||
IMetricsInfo getMetrics();
|
IMetricsInfo getMetrics();
|
||||||
|
|
||||||
interface IBedrockConfiguration {
|
interface IBedrockConfiguration {
|
||||||
|
@ -133,6 +139,8 @@ public interface GeyserConfiguration {
|
||||||
|
|
||||||
int getMtu();
|
int getMtu();
|
||||||
|
|
||||||
|
boolean isUseAdapters();
|
||||||
|
|
||||||
int getConfigVersion();
|
int getConfigVersion();
|
||||||
|
|
||||||
static void checkGeyserConfiguration(GeyserConfiguration geyserConfig, GeyserLogger geyserLogger) {
|
static void checkGeyserConfiguration(GeyserConfiguration geyserConfig, GeyserLogger geyserLogger) {
|
||||||
|
|
|
@ -89,6 +89,9 @@ public abstract class GeyserJacksonConfiguration implements GeyserConfiguration
|
||||||
@JsonProperty("show-cooldown")
|
@JsonProperty("show-cooldown")
|
||||||
private boolean showCooldown = true;
|
private boolean showCooldown = true;
|
||||||
|
|
||||||
|
@JsonProperty("show-coordinates")
|
||||||
|
private boolean showCoordinates = true;
|
||||||
|
|
||||||
@JsonProperty("allow-third-party-ears")
|
@JsonProperty("allow-third-party-ears")
|
||||||
private boolean allowThirdPartyEars = false;
|
private boolean allowThirdPartyEars = false;
|
||||||
|
|
||||||
|
@ -101,12 +104,18 @@ public abstract class GeyserJacksonConfiguration implements GeyserConfiguration
|
||||||
@JsonProperty("cache-images")
|
@JsonProperty("cache-images")
|
||||||
private int cacheImages = 0;
|
private int cacheImages = 0;
|
||||||
|
|
||||||
|
@JsonProperty("allow-custom-skulls")
|
||||||
|
private boolean allowCustomSkulls = true;
|
||||||
|
|
||||||
@JsonProperty("above-bedrock-nether-building")
|
@JsonProperty("above-bedrock-nether-building")
|
||||||
private boolean aboveBedrockNetherBuilding = false;
|
private boolean aboveBedrockNetherBuilding = false;
|
||||||
|
|
||||||
@JsonProperty("force-resource-packs")
|
@JsonProperty("force-resource-packs")
|
||||||
private boolean forceResourcePacks = true;
|
private boolean forceResourcePacks = true;
|
||||||
|
|
||||||
|
@JsonProperty("xbox-achievements-enabled")
|
||||||
|
private boolean xboxAchievementsEnabled = false;
|
||||||
|
|
||||||
private MetricsInfo metrics = new MetricsInfo();
|
private MetricsInfo metrics = new MetricsInfo();
|
||||||
|
|
||||||
@Getter
|
@Getter
|
||||||
|
@ -167,6 +176,9 @@ public abstract class GeyserJacksonConfiguration implements GeyserConfiguration
|
||||||
@JsonProperty("mtu")
|
@JsonProperty("mtu")
|
||||||
private int mtu = 1400;
|
private int mtu = 1400;
|
||||||
|
|
||||||
|
@JsonProperty("use-adapters")
|
||||||
|
private boolean useAdapters = true;
|
||||||
|
|
||||||
@JsonProperty("config-version")
|
@JsonProperty("config-version")
|
||||||
private int configVersion = 0;
|
private int configVersion = 0;
|
||||||
}
|
}
|
||||||
|
|
|
@ -27,7 +27,7 @@ package org.geysermc.connector.dump;
|
||||||
|
|
||||||
import lombok.AllArgsConstructor;
|
import lombok.AllArgsConstructor;
|
||||||
import lombok.Getter;
|
import lombok.Getter;
|
||||||
import org.geysermc.connector.common.PlatformType;
|
import org.geysermc.common.PlatformType;
|
||||||
import org.geysermc.connector.GeyserConnector;
|
import org.geysermc.connector.GeyserConnector;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
|
@ -35,6 +35,16 @@ import java.util.concurrent.TimeUnit;
|
||||||
|
|
||||||
public class BoatEntity extends Entity {
|
public class BoatEntity extends Entity {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Required when IS_BUOYANT is sent in order for boats to work in the water. <br>
|
||||||
|
*
|
||||||
|
* Taken from BDS 1.16.200, with the modification of <code>simulate_waves</code> since Java doesn't bob the boat up and down
|
||||||
|
* like Bedrock.
|
||||||
|
*/
|
||||||
|
private static final String BUOYANCY_DATA = "{\"apply_gravity\":true,\"base_buoyancy\":1.0,\"big_wave_probability\":0.02999999932944775," +
|
||||||
|
"\"big_wave_speed\":10.0,\"drag_down_on_buoyancy_removed\":0.0,\"liquid_blocks\":[\"minecraft:water\"," +
|
||||||
|
"\"minecraft:flowing_water\"],\"simulate_waves\":false}}";
|
||||||
|
|
||||||
private boolean isPaddlingLeft;
|
private boolean isPaddlingLeft;
|
||||||
private float paddleTimeLeft;
|
private float paddleTimeLeft;
|
||||||
private boolean isPaddlingRight;
|
private boolean isPaddlingRight;
|
||||||
|
@ -45,6 +55,10 @@ public class BoatEntity extends Entity {
|
||||||
|
|
||||||
public BoatEntity(long entityId, long geyserId, EntityType entityType, Vector3f position, Vector3f motion, Vector3f rotation) {
|
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(90, 0, 90));
|
super(entityId, geyserId, entityType, position.add(0d, entityType.getOffset(), 0d), motion, rotation.add(90, 0, 90));
|
||||||
|
|
||||||
|
// Required to be able to move on land 1.16.200+ or apply gravity not in the water 1.16.100+
|
||||||
|
metadata.put(EntityData.IS_BUOYANT, (byte) 1);
|
||||||
|
metadata.put(EntityData.BUOYANCY_DATA, BUOYANCY_DATA);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -26,13 +26,13 @@
|
||||||
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.metadata.EntityMetadata;
|
||||||
import com.github.steveice10.mc.protocol.data.message.Message;
|
|
||||||
import com.nukkitx.math.vector.Vector3f;
|
import com.nukkitx.math.vector.Vector3f;
|
||||||
import com.nukkitx.protocol.bedrock.data.entity.EntityData;
|
import com.nukkitx.protocol.bedrock.data.entity.EntityData;
|
||||||
|
import net.kyori.adventure.text.Component;
|
||||||
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.world.block.BlockTranslator;
|
import org.geysermc.connector.network.translators.world.block.BlockTranslator;
|
||||||
import org.geysermc.connector.utils.MessageUtils;
|
import org.geysermc.connector.network.translators.chat.MessageTranslator;
|
||||||
|
|
||||||
public class CommandBlockMinecartEntity extends DefaultBlockMinecartEntity {
|
public class CommandBlockMinecartEntity extends DefaultBlockMinecartEntity {
|
||||||
|
|
||||||
|
@ -51,7 +51,7 @@ public class CommandBlockMinecartEntity extends DefaultBlockMinecartEntity {
|
||||||
metadata.put(EntityData.COMMAND_BLOCK_COMMAND, entityMetadata.getValue());
|
metadata.put(EntityData.COMMAND_BLOCK_COMMAND, entityMetadata.getValue());
|
||||||
}
|
}
|
||||||
if (entityMetadata.getId() == 14) {
|
if (entityMetadata.getId() == 14) {
|
||||||
metadata.put(EntityData.COMMAND_BLOCK_LAST_OUTPUT, MessageUtils.getBedrockMessage((Message) entityMetadata.getValue()));
|
metadata.put(EntityData.COMMAND_BLOCK_LAST_OUTPUT, MessageTranslator.convertMessage((Component) entityMetadata.getValue()));
|
||||||
}
|
}
|
||||||
super.updateBedrockMetadata(entityMetadata, session);
|
super.updateBedrockMetadata(entityMetadata, session);
|
||||||
}
|
}
|
||||||
|
|
|
@ -39,6 +39,8 @@ public class EnderCrystalEntity extends Entity {
|
||||||
public EnderCrystalEntity(long entityId, long geyserId, EntityType entityType, Vector3f position, Vector3f motion, Vector3f rotation) {
|
public EnderCrystalEntity(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);
|
||||||
|
|
||||||
|
// Bedrock 1.16.100+ - prevents the entity from appearing on fire itself when fire is underneath it
|
||||||
|
metadata.getFlags().setFlag(EntityFlag.FIRE_IMMUNE, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -32,11 +32,9 @@ 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.message.Message;
|
|
||||||
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.math.vector.Vector3i;
|
|
||||||
import com.nukkitx.protocol.bedrock.data.AttributeData;
|
import com.nukkitx.protocol.bedrock.data.AttributeData;
|
||||||
import com.nukkitx.protocol.bedrock.data.entity.EntityData;
|
import com.nukkitx.protocol.bedrock.data.entity.EntityData;
|
||||||
import com.nukkitx.protocol.bedrock.data.entity.EntityDataMap;
|
import com.nukkitx.protocol.bedrock.data.entity.EntityDataMap;
|
||||||
|
@ -46,16 +44,17 @@ import com.nukkitx.protocol.bedrock.packet.*;
|
||||||
import it.unimi.dsi.fastutil.longs.LongOpenHashSet;
|
import it.unimi.dsi.fastutil.longs.LongOpenHashSet;
|
||||||
import lombok.Getter;
|
import lombok.Getter;
|
||||||
import lombok.Setter;
|
import lombok.Setter;
|
||||||
|
import net.kyori.adventure.text.Component;
|
||||||
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.living.ArmorStandEntity;
|
||||||
|
import org.geysermc.connector.entity.player.PlayerEntity;
|
||||||
import org.geysermc.connector.entity.type.EntityType;
|
import org.geysermc.connector.entity.type.EntityType;
|
||||||
import org.geysermc.connector.inventory.PlayerInventory;
|
import org.geysermc.connector.inventory.PlayerInventory;
|
||||||
import org.geysermc.connector.network.session.GeyserSession;
|
import org.geysermc.connector.network.session.GeyserSession;
|
||||||
import org.geysermc.connector.network.translators.item.ItemRegistry;
|
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.network.translators.chat.MessageTranslator;
|
||||||
import org.geysermc.connector.utils.MessageUtils;
|
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
|
@ -68,8 +67,6 @@ public class Entity {
|
||||||
protected long entityId;
|
protected long entityId;
|
||||||
protected long geyserId;
|
protected long geyserId;
|
||||||
|
|
||||||
protected String dimension;
|
|
||||||
|
|
||||||
protected Vector3f position;
|
protected Vector3f position;
|
||||||
protected Vector3f motion;
|
protected Vector3f motion;
|
||||||
|
|
||||||
|
@ -101,7 +98,6 @@ public class Entity {
|
||||||
this.rotation = rotation;
|
this.rotation = rotation;
|
||||||
|
|
||||||
this.valid = false;
|
this.valid = false;
|
||||||
this.dimension = "minecraft:overworld";
|
|
||||||
|
|
||||||
setPosition(position);
|
setPosition(position);
|
||||||
|
|
||||||
|
@ -319,11 +315,11 @@ public class Entity {
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case 2: // custom name
|
case 2: // custom name
|
||||||
if (entityMetadata.getValue() instanceof Message) {
|
if (entityMetadata.getValue() instanceof Component) {
|
||||||
Message message = (Message) entityMetadata.getValue();
|
Component message = (Component) entityMetadata.getValue();
|
||||||
if (message != null)
|
if (message != null)
|
||||||
// Always translate even if it's a TextMessage since there could be translatable parameters
|
// Always translate even if it's a TextMessage since there could be translatable parameters
|
||||||
metadata.put(EntityData.NAMETAG, MessageUtils.getTranslatedBedrockMessage(message, session.getClientData().getLanguageCode(), true));
|
metadata.put(EntityData.NAMETAG, MessageTranslator.convertMessage(message, session.getLocale()));
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case 3: // is custom name visible
|
case 3: // is custom name visible
|
||||||
|
@ -341,18 +337,6 @@ public class Entity {
|
||||||
metadata.getFlags().setFlag(EntityFlag.SLEEPING, true);
|
metadata.getFlags().setFlag(EntityFlag.SLEEPING, true);
|
||||||
// Has to be a byte or it does not work
|
// Has to be a byte or it does not work
|
||||||
metadata.put(EntityData.PLAYER_FLAGS, (byte) 2);
|
metadata.put(EntityData.PLAYER_FLAGS, (byte) 2);
|
||||||
if (entityId == session.getPlayerEntity().getEntityId()) {
|
|
||||||
Vector3i lastInteractionPos = session.getLastInteractionPosition();
|
|
||||||
metadata.put(EntityData.BED_POSITION, lastInteractionPos);
|
|
||||||
if (session.getConnector().getConfig().isCacheChunks()) {
|
|
||||||
int 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_POSITION, Vector3i.from(position.getFloorX(), position.getFloorY() - 2, position.getFloorZ()));
|
|
||||||
}
|
|
||||||
metadata.put(EntityData.BOUNDING_BOX_WIDTH, 0.2f);
|
metadata.put(EntityData.BOUNDING_BOX_WIDTH, 0.2f);
|
||||||
metadata.put(EntityData.BOUNDING_BOX_HEIGHT, 0.2f);
|
metadata.put(EntityData.BOUNDING_BOX_HEIGHT, 0.2f);
|
||||||
} else if (metadata.getFlags().getFlag(EntityFlag.SLEEPING)) {
|
} else if (metadata.getFlags().getFlag(EntityFlag.SLEEPING)) {
|
||||||
|
|
|
@ -36,6 +36,7 @@ import com.nukkitx.nbt.NbtMapBuilder;
|
||||||
import com.nukkitx.nbt.NbtType;
|
import com.nukkitx.nbt.NbtType;
|
||||||
import com.nukkitx.protocol.bedrock.data.entity.EntityData;
|
import com.nukkitx.protocol.bedrock.data.entity.EntityData;
|
||||||
import com.nukkitx.protocol.bedrock.packet.SetEntityMotionPacket;
|
import com.nukkitx.protocol.bedrock.packet.SetEntityMotionPacket;
|
||||||
|
import org.geysermc.connector.entity.player.PlayerEntity;
|
||||||
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.FireworkColor;
|
import org.geysermc.connector.utils.FireworkColor;
|
||||||
|
|
|
@ -36,7 +36,20 @@ import org.geysermc.connector.network.translators.item.ItemTranslator;
|
||||||
public class ItemEntity extends Entity {
|
public class ItemEntity extends Entity {
|
||||||
|
|
||||||
public ItemEntity(long entityId, long geyserId, EntityType entityType, Vector3f position, Vector3f motion, Vector3f rotation) {
|
public ItemEntity(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 setMotion(Vector3f motion) {
|
||||||
|
if (isOnGround())
|
||||||
|
motion = Vector3f.from(motion.getX(), 0, motion.getZ());
|
||||||
|
|
||||||
|
super.setMotion(motion);
|
||||||
|
}
|
||||||
|
|
||||||
|
@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);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -44,7 +57,7 @@ public class ItemEntity extends Entity {
|
||||||
if (entityMetadata.getId() == 7) {
|
if (entityMetadata.getId() == 7) {
|
||||||
AddItemEntityPacket itemPacket = new AddItemEntityPacket();
|
AddItemEntityPacket itemPacket = new AddItemEntityPacket();
|
||||||
itemPacket.setRuntimeEntityId(geyserId);
|
itemPacket.setRuntimeEntityId(geyserId);
|
||||||
itemPacket.setPosition(position);
|
itemPacket.setPosition(position.add(0d, this.entityType.getOffset(), 0d));
|
||||||
itemPacket.setMotion(motion);
|
itemPacket.setMotion(motion);
|
||||||
itemPacket.setUniqueEntityId(geyserId);
|
itemPacket.setUniqueEntityId(geyserId);
|
||||||
itemPacket.setFromFishing(false);
|
itemPacket.setFromFishing(false);
|
||||||
|
|
|
@ -69,7 +69,6 @@ public class ItemFrameEntity extends Entity {
|
||||||
|
|
||||||
public ItemFrameEntity(long entityId, long geyserId, EntityType entityType, Vector3f position, Vector3f motion, Vector3f rotation, HangingDirection direction) {
|
public ItemFrameEntity(long entityId, long geyserId, EntityType entityType, Vector3f position, Vector3f motion, Vector3f rotation, HangingDirection direction) {
|
||||||
super(entityId, geyserId, entityType, position, motion, rotation);
|
super(entityId, geyserId, entityType, position, motion, rotation);
|
||||||
NbtMapBuilder builder = NbtMap.builder();
|
|
||||||
NbtMapBuilder blockBuilder = NbtMap.builder()
|
NbtMapBuilder blockBuilder = NbtMap.builder()
|
||||||
.putString("name", "minecraft:frame")
|
.putString("name", "minecraft:frame")
|
||||||
.putInt("version", BlockTranslator.getBlockStateVersion());
|
.putInt("version", BlockTranslator.getBlockStateVersion());
|
||||||
|
@ -77,9 +76,7 @@ public class ItemFrameEntity extends Entity {
|
||||||
.putInt("facing_direction", direction.ordinal())
|
.putInt("facing_direction", direction.ordinal())
|
||||||
.putByte("item_frame_map_bit", (byte) 0)
|
.putByte("item_frame_map_bit", (byte) 0)
|
||||||
.build());
|
.build());
|
||||||
builder.put("block", blockBuilder.build());
|
bedrockRuntimeId = BlockTranslator.getItemFrame(blockBuilder.build());
|
||||||
builder.putShort("id", (short) 199);
|
|
||||||
bedrockRuntimeId = BlockTranslator.getItemFrame(builder.build());
|
|
||||||
bedrockPosition = Vector3i.from(position.getFloorX(), position.getFloorY(), position.getFloorZ());
|
bedrockPosition = Vector3i.from(position.getFloorX(), position.getFloorY(), position.getFloorZ());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -101,14 +98,12 @@ public class ItemFrameEntity extends Entity {
|
||||||
ItemEntry itemEntry = ItemRegistry.getItem((ItemStack) entityMetadata.getValue());
|
ItemEntry itemEntry = ItemRegistry.getItem((ItemStack) entityMetadata.getValue());
|
||||||
NbtMapBuilder builder = NbtMap.builder();
|
NbtMapBuilder builder = NbtMap.builder();
|
||||||
|
|
||||||
String blockName = ItemRegistry.getBedrockIdentifer(itemEntry);
|
|
||||||
|
|
||||||
builder.putByte("Count", (byte) itemData.getCount());
|
builder.putByte("Count", (byte) itemData.getCount());
|
||||||
if (itemData.getTag() != null) {
|
if (itemData.getTag() != null) {
|
||||||
builder.put("tag", itemData.getTag().toBuilder().build());
|
builder.put("tag", itemData.getTag().toBuilder().build());
|
||||||
}
|
}
|
||||||
builder.putShort("Damage", itemData.getDamage());
|
builder.putShort("Damage", itemData.getDamage());
|
||||||
builder.putString("Name", blockName);
|
builder.putString("Name", itemEntry.getBedrockIdentifier());
|
||||||
NbtMapBuilder tag = getDefaultTag().toBuilder();
|
NbtMapBuilder tag = getDefaultTag().toBuilder();
|
||||||
tag.put("Item", builder.build());
|
tag.put("Item", builder.build());
|
||||||
tag.putFloat("ItemDropChance", 1.0f);
|
tag.putFloat("ItemDropChance", 1.0f);
|
||||||
|
@ -141,7 +136,7 @@ public class ItemFrameEntity extends Entity {
|
||||||
UpdateBlockPacket updateBlockPacket = new UpdateBlockPacket();
|
UpdateBlockPacket updateBlockPacket = new UpdateBlockPacket();
|
||||||
updateBlockPacket.setDataLayer(0);
|
updateBlockPacket.setDataLayer(0);
|
||||||
updateBlockPacket.setBlockPosition(bedrockPosition);
|
updateBlockPacket.setBlockPosition(bedrockPosition);
|
||||||
updateBlockPacket.setRuntimeId(0);
|
updateBlockPacket.setRuntimeId(BlockTranslator.BEDROCK_AIR_ID);
|
||||||
updateBlockPacket.getFlags().add(UpdateBlockPacket.Flag.PRIORITY);
|
updateBlockPacket.getFlags().add(UpdateBlockPacket.Flag.PRIORITY);
|
||||||
updateBlockPacket.getFlags().add(UpdateBlockPacket.Flag.NETWORK);
|
updateBlockPacket.getFlags().add(UpdateBlockPacket.Flag.NETWORK);
|
||||||
updateBlockPacket.getFlags().add(UpdateBlockPacket.Flag.NEIGHBORS);
|
updateBlockPacket.getFlags().add(UpdateBlockPacket.Flag.NEIGHBORS);
|
||||||
|
@ -196,18 +191,6 @@ public class ItemFrameEntity extends Entity {
|
||||||
return session.getItemFrameCache().getOrDefault(position, -1);
|
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.
|
* Force-remove from the position-to-ID map so it doesn't cause conflicts.
|
||||||
* @param session GeyserSession.
|
* @param session GeyserSession.
|
||||||
|
|
|
@ -27,10 +27,24 @@ package org.geysermc.connector.entity;
|
||||||
|
|
||||||
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;
|
||||||
|
import org.geysermc.connector.network.session.GeyserSession;
|
||||||
|
|
||||||
public class ItemedFireballEntity extends Entity {
|
public class ItemedFireballEntity extends ThrowableEntity {
|
||||||
|
private final Vector3f acceleration;
|
||||||
|
|
||||||
public ItemedFireballEntity(long entityId, long geyserId, EntityType entityType, Vector3f position, Vector3f motion, Vector3f rotation) {
|
public ItemedFireballEntity(long entityId, long geyserId, EntityType entityType, Vector3f position, Vector3f motion, Vector3f rotation) {
|
||||||
super(entityId, geyserId, entityType, position, motion, rotation);
|
super(entityId, geyserId, entityType, position, Vector3f.ZERO, rotation);
|
||||||
|
acceleration = motion;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void updatePosition(GeyserSession session) {
|
||||||
|
position = position.add(motion);
|
||||||
|
// TODO: While this reduces latency in position updating (needed for better fireball reflecting),
|
||||||
|
// TODO: movement is incredibly stiff. See if the MoveEntityDeltaPacket in 1.16.100 fixes this, and if not,
|
||||||
|
// TODO: only use this laggy movement for fireballs that be reflected
|
||||||
|
moveAbsoluteImmediate(session, position, rotation, false, true);
|
||||||
|
float drag = getDrag(session);
|
||||||
|
motion = motion.add(acceleration).mul(drag);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -26,7 +26,9 @@
|
||||||
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.metadata.EntityMetadata;
|
||||||
|
import com.github.steveice10.mc.protocol.data.game.entity.metadata.Position;
|
||||||
import com.nukkitx.math.vector.Vector3f;
|
import com.nukkitx.math.vector.Vector3f;
|
||||||
|
import com.nukkitx.math.vector.Vector3i;
|
||||||
import com.nukkitx.protocol.bedrock.data.AttributeData;
|
import com.nukkitx.protocol.bedrock.data.AttributeData;
|
||||||
import com.nukkitx.protocol.bedrock.data.entity.EntityData;
|
import com.nukkitx.protocol.bedrock.data.entity.EntityData;
|
||||||
import com.nukkitx.protocol.bedrock.data.entity.EntityFlag;
|
import com.nukkitx.protocol.bedrock.data.entity.EntityFlag;
|
||||||
|
@ -42,6 +44,7 @@ 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.ItemRegistry;
|
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 java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
@ -74,6 +77,9 @@ public class LivingEntity extends Entity {
|
||||||
getHand().equals(ItemData.AIR) && getOffHand().getId() == ItemRegistry.SHIELD.getBedrockId());
|
getHand().equals(ItemData.AIR) && getOffHand().getId() == ItemRegistry.SHIELD.getBedrockId());
|
||||||
metadata.getFlags().setFlag(EntityFlag.USING_ITEM, (xd & 0x01) == 0x01 && !isUsingShield);
|
metadata.getFlags().setFlag(EntityFlag.USING_ITEM, (xd & 0x01) == 0x01 && !isUsingShield);
|
||||||
metadata.getFlags().setFlag(EntityFlag.BLOCKING, (xd & 0x01) == 0x01);
|
metadata.getFlags().setFlag(EntityFlag.BLOCKING, (xd & 0x01) == 0x01);
|
||||||
|
|
||||||
|
// Riptide spin attack
|
||||||
|
metadata.getFlags().setFlag(EntityFlag.DAMAGE_NEARBY_MOBS, (xd & 0x04) == 0x04);
|
||||||
break;
|
break;
|
||||||
case 8:
|
case 8:
|
||||||
metadata.put(EntityData.HEALTH, entityMetadata.getValue());
|
metadata.put(EntityData.HEALTH, entityMetadata.getValue());
|
||||||
|
@ -84,6 +90,17 @@ public class LivingEntity extends Entity {
|
||||||
case 10:
|
case 10:
|
||||||
metadata.put(EntityData.EFFECT_AMBIENT, (byte) ((boolean) entityMetadata.getValue() ? 1 : 0));
|
metadata.put(EntityData.EFFECT_AMBIENT, (byte) ((boolean) entityMetadata.getValue() ? 1 : 0));
|
||||||
break;
|
break;
|
||||||
|
case 13: // Bed Position
|
||||||
|
Position bedPosition = (Position) entityMetadata.getValue();
|
||||||
|
if (bedPosition != null) {
|
||||||
|
metadata.put(EntityData.BED_POSITION, Vector3i.from(bedPosition.getX(), bedPosition.getY(), bedPosition.getZ()));
|
||||||
|
if (session.getConnector().getConfig().isCacheChunks()) {
|
||||||
|
int bed = session.getConnector().getWorldManager().getBlockAt(session, bedPosition);
|
||||||
|
// Bed has to be updated, or else player is floating in the air
|
||||||
|
ChunkUtils.updateBlock(session, bed, bedPosition);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
super.updateBedrockMetadata(entityMetadata, session);
|
super.updateBedrockMetadata(entityMetadata, session);
|
||||||
|
|
|
@ -26,11 +26,140 @@
|
||||||
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.data.LevelEventType;
|
||||||
|
import com.nukkitx.protocol.bedrock.data.entity.EntityFlag;
|
||||||
|
import com.nukkitx.protocol.bedrock.packet.LevelEventPacket;
|
||||||
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;
|
||||||
|
|
||||||
|
import java.util.concurrent.ScheduledFuture;
|
||||||
|
import java.util.concurrent.TimeUnit;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Used as a class for any object-like entity that moves as a projectile
|
||||||
|
*/
|
||||||
public class ThrowableEntity extends Entity {
|
public class ThrowableEntity extends Entity {
|
||||||
|
|
||||||
|
private Vector3f lastPosition;
|
||||||
|
/**
|
||||||
|
* Updates the position for the Bedrock client.
|
||||||
|
*
|
||||||
|
* Java clients assume the next positions of moving items. Bedrock needs to be explicitly told positions
|
||||||
|
*/
|
||||||
|
protected ScheduledFuture<?> positionUpdater;
|
||||||
|
|
||||||
public ThrowableEntity(long entityId, long geyserId, EntityType entityType, Vector3f position, Vector3f motion, Vector3f rotation) {
|
public ThrowableEntity(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);
|
||||||
|
this.lastPosition = position;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void spawnEntity(GeyserSession session) {
|
||||||
|
super.spawnEntity(session);
|
||||||
|
positionUpdater = session.getConnector().getGeneralThreadPool().scheduleAtFixedRate(() -> {
|
||||||
|
if (session.isClosed()) {
|
||||||
|
positionUpdater.cancel(true);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
updatePosition(session);
|
||||||
|
}, 0, 50, TimeUnit.MILLISECONDS);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void moveAbsoluteImmediate(GeyserSession session, Vector3f position, Vector3f rotation, boolean isOnGround, boolean teleported) {
|
||||||
|
super.moveAbsolute(session, position, rotation, isOnGround, teleported);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void updatePosition(GeyserSession session) {
|
||||||
|
super.moveRelative(session, motion.getX(), motion.getY(), motion.getZ(), rotation, onGround);
|
||||||
|
float drag = getDrag(session);
|
||||||
|
float gravity = getGravity();
|
||||||
|
motion = motion.mul(drag).down(gravity);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the gravity of this entity type. Used for applying gravity while the entity is in motion.
|
||||||
|
*
|
||||||
|
* @return the amount of gravity to apply to this entity while in motion.
|
||||||
|
*/
|
||||||
|
protected float getGravity() {
|
||||||
|
if (metadata.getFlags().getFlag(EntityFlag.HAS_GRAVITY)) {
|
||||||
|
switch (entityType) {
|
||||||
|
case THROWN_POTION:
|
||||||
|
case LINGERING_POTION:
|
||||||
|
return 0.05f;
|
||||||
|
case THROWN_EXP_BOTTLE:
|
||||||
|
return 0.07f;
|
||||||
|
case FIREBALL:
|
||||||
|
return 0;
|
||||||
|
case SNOWBALL:
|
||||||
|
case THROWN_EGG:
|
||||||
|
case THROWN_ENDERPEARL:
|
||||||
|
return 0.03f;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param session the session of the Bedrock client.
|
||||||
|
* @return the drag that should be multiplied to the entity's motion
|
||||||
|
*/
|
||||||
|
protected float getDrag(GeyserSession session) {
|
||||||
|
if (isInWater(session)) {
|
||||||
|
return 0.8f;
|
||||||
|
} else {
|
||||||
|
switch (entityType) {
|
||||||
|
case THROWN_POTION:
|
||||||
|
case LINGERING_POTION:
|
||||||
|
case THROWN_EXP_BOTTLE:
|
||||||
|
case SNOWBALL:
|
||||||
|
case THROWN_EGG:
|
||||||
|
case THROWN_ENDERPEARL:
|
||||||
|
return 0.99f;
|
||||||
|
case FIREBALL:
|
||||||
|
case SMALL_FIREBALL:
|
||||||
|
case DRAGON_FIREBALL:
|
||||||
|
return 0.95f;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param session the session of the Bedrock client.
|
||||||
|
* @return true if this entity is currently in water.
|
||||||
|
*/
|
||||||
|
protected boolean isInWater(GeyserSession session) {
|
||||||
|
if (session.getConnector().getConfig().isCacheChunks()) {
|
||||||
|
int block = session.getConnector().getWorldManager().getBlockAt(session, position.toInt());
|
||||||
|
return block == BlockTranslator.BEDROCK_WATER_ID;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean despawnEntity(GeyserSession session) {
|
||||||
|
positionUpdater.cancel(true);
|
||||||
|
if (entityType == EntityType.THROWN_ENDERPEARL) {
|
||||||
|
LevelEventPacket particlePacket = new LevelEventPacket();
|
||||||
|
particlePacket.setType(LevelEventType.PARTICLE_TELEPORT);
|
||||||
|
particlePacket.setPosition(position);
|
||||||
|
session.sendUpstreamPacket(particlePacket);
|
||||||
|
}
|
||||||
|
return super.despawnEntity(session);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void moveRelative(GeyserSession session, double relX, double relY, double relZ, Vector3f rotation, boolean isOnGround) {
|
||||||
|
position = lastPosition;
|
||||||
|
super.moveRelative(session, relX, relY, relZ, rotation, isOnGround);
|
||||||
|
lastPosition = position;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void moveAbsolute(GeyserSession session, Vector3f position, Vector3f rotation, boolean isOnGround, boolean teleported) {
|
||||||
|
super.moveAbsolute(session, position, rotation, isOnGround, teleported);
|
||||||
|
lastPosition = position;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,58 @@
|
||||||
|
/*
|
||||||
|
* 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 org.geysermc.connector.entity.type.EntityType;
|
||||||
|
import org.geysermc.connector.network.session.GeyserSession;
|
||||||
|
|
||||||
|
public class WitherSkullEntity extends ItemedFireballEntity {
|
||||||
|
private boolean isCharged;
|
||||||
|
|
||||||
|
public WitherSkullEntity(long entityId, long geyserId, EntityType entityType, Vector3f position, Vector3f motion, Vector3f rotation) {
|
||||||
|
super(entityId, geyserId, entityType, position, motion, rotation);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected float getDrag(GeyserSession session) {
|
||||||
|
return isCharged ? 0.73f : super.getDrag(session);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void updateBedrockMetadata(EntityMetadata entityMetadata, GeyserSession session) {
|
||||||
|
if (entityMetadata.getId() == 7) {
|
||||||
|
boolean newIsCharged = (boolean) entityMetadata.getValue();
|
||||||
|
if (newIsCharged != isCharged) {
|
||||||
|
isCharged = newIsCharged;
|
||||||
|
entityType = isCharged ? EntityType.WITHER_SKULL_DANGEROUS : EntityType.WITHER_SKULL;
|
||||||
|
despawnEntity(session);
|
||||||
|
spawnEntity(session);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
super.updateBedrockMetadata(entityMetadata, session);
|
||||||
|
}
|
||||||
|
}
|
|
@ -29,6 +29,7 @@ import com.github.steveice10.mc.protocol.data.game.entity.metadata.EntityMetadat
|
||||||
import com.github.steveice10.mc.protocol.data.game.entity.metadata.MetadataType;
|
import com.github.steveice10.mc.protocol.data.game.entity.metadata.MetadataType;
|
||||||
import com.nukkitx.math.vector.Vector3f;
|
import com.nukkitx.math.vector.Vector3f;
|
||||||
import com.nukkitx.protocol.bedrock.data.entity.EntityData;
|
import com.nukkitx.protocol.bedrock.data.entity.EntityData;
|
||||||
|
import lombok.Getter;
|
||||||
import org.geysermc.connector.entity.LivingEntity;
|
import org.geysermc.connector.entity.LivingEntity;
|
||||||
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;
|
||||||
|
@ -36,6 +37,7 @@ import org.geysermc.connector.network.session.GeyserSession;
|
||||||
public class ArmorStandEntity extends LivingEntity {
|
public class ArmorStandEntity extends LivingEntity {
|
||||||
|
|
||||||
// These are used to store the state of the armour stand for use when handling invisibility
|
// These are used to store the state of the armour stand for use when handling invisibility
|
||||||
|
@Getter
|
||||||
private boolean isMarker = false;
|
private boolean isMarker = false;
|
||||||
private boolean isInvisible = false;
|
private boolean isInvisible = false;
|
||||||
private boolean isSmall = false;
|
private boolean isSmall = false;
|
||||||
|
@ -47,11 +49,11 @@ public class ArmorStandEntity extends LivingEntity {
|
||||||
@Override
|
@Override
|
||||||
public void moveAbsolute(GeyserSession session, Vector3f position, Vector3f rotation, boolean isOnGround, boolean teleported) {
|
public void moveAbsolute(GeyserSession session, Vector3f position, Vector3f rotation, boolean isOnGround, boolean teleported) {
|
||||||
// Fake the height to be above where it is so the nametag appears in the right location for invisible non-marker armour stands
|
// Fake the height to be above where it is so the nametag appears in the right location for invisible non-marker armour stands
|
||||||
if (!isMarker && isInvisible) {
|
if (!isMarker && isInvisible && passengers.isEmpty()) {
|
||||||
position = position.add(0d, entityType.getHeight() * (isSmall ? 0.55d : 1d), 0d);
|
position = position.add(0d, entityType.getHeight() * (isSmall ? 0.55d : 1d), 0d);
|
||||||
}
|
}
|
||||||
|
|
||||||
super.moveAbsolute(session, position, rotation, isOnGround, teleported);
|
super.moveAbsolute(session, position, Vector3f.from(rotation.getX(), rotation.getX(), rotation.getX()), isOnGround, teleported);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -93,4 +95,10 @@ public class ArmorStandEntity extends LivingEntity {
|
||||||
}
|
}
|
||||||
super.updateBedrockMetadata(entityMetadata, session);
|
super.updateBedrockMetadata(entityMetadata, session);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void spawnEntity(GeyserSession session) {
|
||||||
|
this.rotation = Vector3f.from(rotation.getX(), rotation.getX(), rotation.getX());
|
||||||
|
super.spawnEntity(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.entity.EntityFlag;
|
||||||
|
import org.geysermc.connector.entity.type.EntityType;
|
||||||
|
import org.geysermc.connector.network.session.GeyserSession;
|
||||||
|
|
||||||
|
public class BatEntity extends AmbientEntity {
|
||||||
|
|
||||||
|
public BatEntity(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) {
|
||||||
|
byte xd = (byte) entityMetadata.getValue();
|
||||||
|
metadata.getFlags().setFlag(EntityFlag.RESTING, (xd & 0x01) == 0x01);
|
||||||
|
}
|
||||||
|
super.updateBedrockMetadata(entityMetadata, session);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,49 @@
|
||||||
|
/*
|
||||||
|
* 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.entity.EntityFlag;
|
||||||
|
import org.geysermc.connector.entity.type.EntityType;
|
||||||
|
import org.geysermc.connector.network.session.GeyserSession;
|
||||||
|
|
||||||
|
public class SnowGolemEntity extends GolemEntity {
|
||||||
|
|
||||||
|
public SnowGolemEntity(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) {
|
||||||
|
byte xd = (byte) entityMetadata.getValue();
|
||||||
|
// Handle the visibility of the pumpkin
|
||||||
|
metadata.getFlags().setFlag(EntityFlag.SHEARED, (xd & 0x10) != 0x10);
|
||||||
|
}
|
||||||
|
super.updateBedrockMetadata(entityMetadata, session);
|
||||||
|
}
|
||||||
|
}
|
|
@ -27,7 +27,10 @@ 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.entity.EntityData;
|
||||||
|
import com.nukkitx.protocol.bedrock.data.entity.EntityEventType;
|
||||||
import com.nukkitx.protocol.bedrock.data.entity.EntityFlag;
|
import com.nukkitx.protocol.bedrock.data.entity.EntityFlag;
|
||||||
|
import com.nukkitx.protocol.bedrock.packet.EntityEventPacket;
|
||||||
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,10 +44,23 @@ public class BeeEntity extends AnimalEntity {
|
||||||
public void updateBedrockMetadata(EntityMetadata entityMetadata, GeyserSession session) {
|
public void updateBedrockMetadata(EntityMetadata entityMetadata, GeyserSession session) {
|
||||||
if (entityMetadata.getId() == 16) {
|
if (entityMetadata.getId() == 16) {
|
||||||
byte xd = (byte) entityMetadata.getValue();
|
byte xd = (byte) entityMetadata.getValue();
|
||||||
metadata.getFlags().setFlag(EntityFlag.ANGRY, (xd & 0x02) == 0x02);
|
// Bee is performing sting attack; trigger animation
|
||||||
|
if ((xd & 0x02) == 0x02) {
|
||||||
|
EntityEventPacket packet = new EntityEventPacket();
|
||||||
|
packet.setRuntimeEntityId(geyserId);
|
||||||
|
packet.setType(EntityEventType.ATTACK_START);
|
||||||
|
packet.setData(0);
|
||||||
|
session.sendUpstreamPacket(packet);
|
||||||
|
}
|
||||||
|
// If the bee has stung
|
||||||
|
metadata.put(EntityData.MARK_VARIANT, (xd & 0x04) == 0x04 ? 1 : 0);
|
||||||
// If the bee has nectar or not
|
// If the bee has nectar or not
|
||||||
metadata.getFlags().setFlag(EntityFlag.POWERED, (xd & 0x08) == 0x08);
|
metadata.getFlags().setFlag(EntityFlag.POWERED, (xd & 0x08) == 0x08);
|
||||||
}
|
}
|
||||||
|
if (entityMetadata.getId() == 17) {
|
||||||
|
// Converting "anger time" to a boolean
|
||||||
|
metadata.getFlags().setFlag(EntityFlag.ANGRY, (int) entityMetadata.getValue() > 0);
|
||||||
|
}
|
||||||
super.updateBedrockMetadata(entityMetadata, session);
|
super.updateBedrockMetadata(entityMetadata, session);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -41,12 +41,13 @@ public class FoxEntity extends AnimalEntity {
|
||||||
@Override
|
@Override
|
||||||
public void updateBedrockMetadata(EntityMetadata entityMetadata, GeyserSession session) {
|
public void updateBedrockMetadata(EntityMetadata entityMetadata, GeyserSession session) {
|
||||||
if (entityMetadata.getId() == 16) {
|
if (entityMetadata.getId() == 16) {
|
||||||
metadata.put(EntityData.VARIANT, (int) entityMetadata.getValue());
|
metadata.put(EntityData.VARIANT, entityMetadata.getValue());
|
||||||
}
|
}
|
||||||
if (entityMetadata.getId() == 17) {
|
if (entityMetadata.getId() == 17) {
|
||||||
byte xd = (byte) entityMetadata.getValue();
|
byte xd = (byte) entityMetadata.getValue();
|
||||||
metadata.getFlags().setFlag(EntityFlag.SITTING, (xd & 0x01) == 0x01);
|
metadata.getFlags().setFlag(EntityFlag.SITTING, (xd & 0x01) == 0x01);
|
||||||
metadata.getFlags().setFlag(EntityFlag.SNEAKING, (xd & 0x04) == 0x04);
|
metadata.getFlags().setFlag(EntityFlag.SNEAKING, (xd & 0x04) == 0x04);
|
||||||
|
metadata.getFlags().setFlag(EntityFlag.INTERESTED, (xd & 0x08) == 0x08);
|
||||||
metadata.getFlags().setFlag(EntityFlag.SLEEPING, (xd & 0x20) == 0x20);
|
metadata.getFlags().setFlag(EntityFlag.SLEEPING, (xd & 0x20) == 0x20);
|
||||||
}
|
}
|
||||||
super.updateBedrockMetadata(entityMetadata, session);
|
super.updateBedrockMetadata(entityMetadata, session);
|
||||||
|
|
|
@ -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.living.animal;
|
||||||
|
|
||||||
|
import com.github.steveice10.mc.protocol.data.game.entity.metadata.EntityMetadata;
|
||||||
|
import com.nukkitx.math.vector.Vector3f;
|
||||||
|
import com.nukkitx.protocol.bedrock.data.entity.EntityFlag;
|
||||||
|
import org.geysermc.connector.entity.type.EntityType;
|
||||||
|
import org.geysermc.connector.network.session.GeyserSession;
|
||||||
|
import org.geysermc.connector.utils.DimensionUtils;
|
||||||
|
|
||||||
|
public class HoglinEntity extends AnimalEntity {
|
||||||
|
|
||||||
|
public HoglinEntity(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() == 16) {
|
||||||
|
// Immune to zombification?
|
||||||
|
// Apply shaking effect if not in the nether and zombification is possible
|
||||||
|
metadata.getFlags().setFlag(EntityFlag.SHAKING, !((boolean) entityMetadata.getValue()) && !session.getDimension().equals(DimensionUtils.NETHER));
|
||||||
|
}
|
||||||
|
super.updateBedrockMetadata(entityMetadata, session);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,47 @@
|
||||||
|
/*
|
||||||
|
* 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.animal;
|
||||||
|
|
||||||
|
import com.github.steveice10.mc.protocol.data.game.entity.metadata.EntityMetadata;
|
||||||
|
import com.nukkitx.math.vector.Vector3f;
|
||||||
|
import com.nukkitx.protocol.bedrock.data.entity.EntityData;
|
||||||
|
import org.geysermc.connector.entity.type.EntityType;
|
||||||
|
import org.geysermc.connector.network.session.GeyserSession;
|
||||||
|
|
||||||
|
public class MooshroomEntity extends AnimalEntity {
|
||||||
|
|
||||||
|
public MooshroomEntity(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() == 16) {
|
||||||
|
metadata.put(EntityData.VARIANT, entityMetadata.getValue().equals("brown") ? 1 : 0);
|
||||||
|
}
|
||||||
|
super.updateBedrockMetadata(entityMetadata, session);
|
||||||
|
}
|
||||||
|
}
|
|
@ -27,23 +27,75 @@ 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.entity.EntityData;
|
||||||
|
import com.nukkitx.protocol.bedrock.data.entity.EntityEventType;
|
||||||
import com.nukkitx.protocol.bedrock.data.entity.EntityFlag;
|
import com.nukkitx.protocol.bedrock.data.entity.EntityFlag;
|
||||||
|
import com.nukkitx.protocol.bedrock.packet.EntityEventPacket;
|
||||||
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.ItemRegistry;
|
||||||
|
|
||||||
public class PandaEntity extends AnimalEntity {
|
public class PandaEntity extends AnimalEntity {
|
||||||
|
|
||||||
|
private int mainGene;
|
||||||
|
private int hiddenGene;
|
||||||
|
|
||||||
public PandaEntity(long entityId, long geyserId, EntityType entityType, Vector3f position, Vector3f motion, Vector3f rotation) {
|
public PandaEntity(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() == 18) {
|
||||||
|
metadata.getFlags().setFlag(EntityFlag.EATING, (int) entityMetadata.getValue() > 0);
|
||||||
|
metadata.put(EntityData.EATING_COUNTER, entityMetadata.getValue());
|
||||||
|
if ((int) entityMetadata.getValue() != 0) {
|
||||||
|
// Particles and sound
|
||||||
|
EntityEventPacket packet = new EntityEventPacket();
|
||||||
|
packet.setRuntimeEntityId(geyserId);
|
||||||
|
packet.setType(EntityEventType.EATING_ITEM);
|
||||||
|
packet.setData(ItemRegistry.BAMBOO.getBedrockId() << 16);
|
||||||
|
session.sendUpstreamPacket(packet);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (entityMetadata.getId() == 19) {
|
||||||
|
mainGene = (int) (byte) entityMetadata.getValue();
|
||||||
|
updateAppearance();
|
||||||
|
}
|
||||||
|
if (entityMetadata.getId() == 20) {
|
||||||
|
hiddenGene = (int) (byte) entityMetadata.getValue();
|
||||||
|
updateAppearance();
|
||||||
|
}
|
||||||
if (entityMetadata.getId() == 21) {
|
if (entityMetadata.getId() == 21) {
|
||||||
byte xd = (byte) entityMetadata.getValue();
|
byte xd = (byte) entityMetadata.getValue();
|
||||||
metadata.getFlags().setFlag(EntityFlag.SNEEZING, (xd & 0x02) == 0x02);
|
metadata.getFlags().setFlag(EntityFlag.SNEEZING, (xd & 0x02) == 0x02);
|
||||||
metadata.getFlags().setFlag(EntityFlag.EATING, (xd & 0x04) == 0x04);
|
metadata.getFlags().setFlag(EntityFlag.ROLLING, (xd & 0x04) == 0x04);
|
||||||
|
metadata.getFlags().setFlag(EntityFlag.SITTING, (xd & 0x08) == 0x08);
|
||||||
|
// Required to put these both for sitting to actually show
|
||||||
|
metadata.put(EntityData.SITTING_AMOUNT, (xd & 0x08) == 0x08 ? 1f : 0f);
|
||||||
|
metadata.put(EntityData.SITTING_AMOUNT_PREVIOUS, (xd & 0x08) == 0x08 ? 1f : 0f);
|
||||||
|
metadata.getFlags().setFlag(EntityFlag.LAYING_DOWN, (xd & 0x10) == 0x10);
|
||||||
}
|
}
|
||||||
super.updateBedrockMetadata(entityMetadata, session);
|
super.updateBedrockMetadata(entityMetadata, session);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Update the panda's appearance, and take into consideration the recessive brown and weak traits that only show up
|
||||||
|
* when both main and hidden genes match
|
||||||
|
*/
|
||||||
|
private void updateAppearance() {
|
||||||
|
if (mainGene == 4 || mainGene == 5) {
|
||||||
|
// Main gene is a recessive trait
|
||||||
|
if (mainGene == hiddenGene) {
|
||||||
|
// Main and hidden genes match; this is what the panda looks like.
|
||||||
|
metadata.put(EntityData.VARIANT, mainGene);
|
||||||
|
} else {
|
||||||
|
// Genes have no effect on appearance
|
||||||
|
metadata.put(EntityData.VARIANT, 0);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// No need to worry about hidden gene
|
||||||
|
metadata.put(EntityData.VARIANT, mainGene);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -48,6 +48,15 @@ public class RabbitEntity extends AnimalEntity {
|
||||||
metadata.put(EntityData.SCALE, .35f);
|
metadata.put(EntityData.SCALE, .35f);
|
||||||
metadata.getFlags().setFlag(EntityFlag.BABY, true);
|
metadata.getFlags().setFlag(EntityFlag.BABY, true);
|
||||||
}
|
}
|
||||||
|
} else if (entityMetadata.getId() == 16) {
|
||||||
|
int variant = (int) entityMetadata.getValue();
|
||||||
|
|
||||||
|
// Change the killer bunny to display as white since it only exists on Java Edition
|
||||||
|
if (variant == 99) {
|
||||||
|
variant = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
metadata.put(EntityData.VARIANT, variant);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -0,0 +1,49 @@
|
||||||
|
/*
|
||||||
|
* 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.animal;
|
||||||
|
|
||||||
|
import com.github.steveice10.mc.protocol.data.game.entity.metadata.EntityMetadata;
|
||||||
|
import com.nukkitx.math.vector.Vector3f;
|
||||||
|
import com.nukkitx.protocol.bedrock.data.entity.EntityFlag;
|
||||||
|
import org.geysermc.connector.entity.type.EntityType;
|
||||||
|
import org.geysermc.connector.network.session.GeyserSession;
|
||||||
|
|
||||||
|
public class TurtleEntity extends AnimalEntity {
|
||||||
|
|
||||||
|
public TurtleEntity(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() == 17) {
|
||||||
|
metadata.getFlags().setFlag(EntityFlag.IS_PREGNANT, (boolean) entityMetadata.getValue());
|
||||||
|
} else if (entityMetadata.getId() == 18) {
|
||||||
|
metadata.getFlags().setFlag(EntityFlag.LAYING_EGG, (boolean) entityMetadata.getValue());
|
||||||
|
}
|
||||||
|
super.updateBedrockMetadata(entityMetadata, session);
|
||||||
|
}
|
||||||
|
}
|
|
@ -27,15 +27,23 @@ 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.entity.EntityData;
|
||||||
|
import com.nukkitx.protocol.bedrock.data.entity.EntityEventType;
|
||||||
import com.nukkitx.protocol.bedrock.data.entity.EntityFlag;
|
import com.nukkitx.protocol.bedrock.data.entity.EntityFlag;
|
||||||
|
import com.nukkitx.protocol.bedrock.data.inventory.ContainerType;
|
||||||
|
import com.nukkitx.protocol.bedrock.packet.EntityEventPacket;
|
||||||
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.network.translators.item.ItemRegistry;
|
||||||
|
|
||||||
public class AbstractHorseEntity extends AnimalEntity {
|
public class AbstractHorseEntity extends AnimalEntity {
|
||||||
|
|
||||||
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);
|
||||||
|
|
||||||
|
// Specifies the size of the entity's inventory. Required to place slots in the entity.
|
||||||
|
metadata.put(EntityData.CONTAINER_BASE_SIZE, 2);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -47,6 +55,33 @@ public class AbstractHorseEntity extends AnimalEntity {
|
||||||
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);
|
metadata.getFlags().setFlag(EntityFlag.STANDING, (xd & 0x20) == 0x20);
|
||||||
|
|
||||||
|
// HorseFlags
|
||||||
|
// Bred 0x10
|
||||||
|
// Eating 0x20
|
||||||
|
// Open mouth 0x80
|
||||||
|
int horseFlags = 0x0;
|
||||||
|
horseFlags = (xd & 0x40) == 0x40 ? horseFlags | 0x80 : horseFlags;
|
||||||
|
|
||||||
|
// Only set eating when we don't have mouth open so a player interaction doesn't trigger the eating animation
|
||||||
|
horseFlags = (xd & 0x10) == 0x10 && (xd & 0x40) != 0x40 ? horseFlags | 0x20 : horseFlags;
|
||||||
|
|
||||||
|
// Set the flags into the display item
|
||||||
|
metadata.put(EntityData.DISPLAY_ITEM, horseFlags);
|
||||||
|
|
||||||
|
// Send the eating particles
|
||||||
|
// We use the wheat metadata as static particles since Java
|
||||||
|
// doesn't send over what item was used to feed the horse
|
||||||
|
if ((xd & 0x40) == 0x40) {
|
||||||
|
EntityEventPacket entityEventPacket = new EntityEventPacket();
|
||||||
|
entityEventPacket.setRuntimeEntityId(geyserId);
|
||||||
|
entityEventPacket.setType(EntityEventType.EATING_ITEM);
|
||||||
|
entityEventPacket.setData(ItemRegistry.WHEAT.getBedrockId() << 16);
|
||||||
|
session.sendUpstreamPacket(entityEventPacket);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set container type if tamed
|
||||||
|
metadata.put(EntityData.CONTAINER_TYPE, ((xd & 0x02) == 0x02) ? (byte) ContainerType.HORSE.getId() : (byte) 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Needed to control horses
|
// Needed to control horses
|
||||||
|
|
|
@ -27,6 +27,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.entity.EntityData;
|
||||||
import com.nukkitx.protocol.bedrock.data.entity.EntityFlag;
|
import com.nukkitx.protocol.bedrock.data.entity.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;
|
||||||
|
@ -35,6 +36,8 @@ public class ChestedHorseEntity extends AbstractHorseEntity {
|
||||||
|
|
||||||
public ChestedHorseEntity(long entityId, long geyserId, EntityType entityType, Vector3f position, Vector3f motion, Vector3f rotation) {
|
public ChestedHorseEntity(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.CONTAINER_BASE_SIZE, 16);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -28,7 +28,6 @@ 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.entity.EntityData;
|
import com.nukkitx.protocol.bedrock.data.entity.EntityData;
|
||||||
import com.nukkitx.protocol.bedrock.data.entity.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,7 +40,7 @@ public class HorseEntity extends AbstractHorseEntity {
|
||||||
@Override
|
@Override
|
||||||
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, entityMetadata.getValue());
|
||||||
metadata.put(EntityData.MARK_VARIANT, (((int) entityMetadata.getValue()) >> 8) % 5);
|
metadata.put(EntityData.MARK_VARIANT, (((int) entityMetadata.getValue()) >> 8) % 5);
|
||||||
}
|
}
|
||||||
super.updateBedrockMetadata(entityMetadata, session);
|
super.updateBedrockMetadata(entityMetadata, session);
|
||||||
|
|
|
@ -38,6 +38,8 @@ public class LlamaEntity extends ChestedHorseEntity {
|
||||||
|
|
||||||
public LlamaEntity(long entityId, long geyserId, EntityType entityType, Vector3f position, Vector3f motion, Vector3f rotation) {
|
public LlamaEntity(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.CONTAINER_STRENGTH_MODIFIER, 3); // Presumably 3 slots for every 1 strength
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -34,6 +34,8 @@ import org.geysermc.connector.network.session.GeyserSession;
|
||||||
|
|
||||||
public class CatEntity extends TameableEntity {
|
public class CatEntity extends TameableEntity {
|
||||||
|
|
||||||
|
private byte collarColor;
|
||||||
|
|
||||||
public CatEntity(long entityId, long geyserId, EntityType entityType, Vector3f position, Vector3f motion, Vector3f rotation) {
|
public CatEntity(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);
|
||||||
}
|
}
|
||||||
|
@ -45,6 +47,13 @@ public class CatEntity extends TameableEntity {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void updateBedrockMetadata(EntityMetadata entityMetadata, GeyserSession session) {
|
public void updateBedrockMetadata(EntityMetadata entityMetadata, GeyserSession session) {
|
||||||
|
super.updateBedrockMetadata(entityMetadata, session);
|
||||||
|
if (entityMetadata.getId() == 16) {
|
||||||
|
// Update collar color if tamed
|
||||||
|
if (metadata.getFlags().getFlag(EntityFlag.TAMED)) {
|
||||||
|
metadata.put(EntityData.COLOR, collarColor);
|
||||||
|
}
|
||||||
|
}
|
||||||
if (entityMetadata.getId() == 18) {
|
if (entityMetadata.getId() == 18) {
|
||||||
// Different colors in Java and Bedrock for some reason
|
// Different colors in Java and Bedrock for some reason
|
||||||
int variantColor;
|
int variantColor;
|
||||||
|
@ -67,11 +76,11 @@ public class CatEntity extends TameableEntity {
|
||||||
metadata.put(EntityData.VARIANT, variantColor);
|
metadata.put(EntityData.VARIANT, variantColor);
|
||||||
}
|
}
|
||||||
if (entityMetadata.getId() == 21) {
|
if (entityMetadata.getId() == 21) {
|
||||||
|
collarColor = (byte) (int) entityMetadata.getValue();
|
||||||
// Needed or else wild cats are a red color
|
// Needed or else wild cats are a red color
|
||||||
if (metadata.getFlags().getFlag(EntityFlag.TAMED)) {
|
if (metadata.getFlags().getFlag(EntityFlag.TAMED)) {
|
||||||
metadata.put(EntityData.COLOR, (byte) (int) entityMetadata.getValue());
|
metadata.put(EntityData.COLOR, collarColor);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
super.updateBedrockMetadata(entityMetadata, session);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -29,10 +29,13 @@ import com.github.steveice10.mc.protocol.data.game.entity.metadata.EntityMetadat
|
||||||
import com.nukkitx.math.vector.Vector3f;
|
import com.nukkitx.math.vector.Vector3f;
|
||||||
import com.nukkitx.protocol.bedrock.data.entity.EntityData;
|
import com.nukkitx.protocol.bedrock.data.entity.EntityData;
|
||||||
import com.nukkitx.protocol.bedrock.data.entity.EntityFlag;
|
import com.nukkitx.protocol.bedrock.data.entity.EntityFlag;
|
||||||
|
import org.geysermc.connector.entity.Entity;
|
||||||
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 java.util.UUID;
|
||||||
|
|
||||||
public class TameableEntity extends AnimalEntity {
|
public class TameableEntity extends AnimalEntity {
|
||||||
|
|
||||||
public TameableEntity(long entityId, long geyserId, EntityType entityType, Vector3f position, Vector3f motion, Vector3f rotation) {
|
public TameableEntity(long entityId, long geyserId, EntityType entityType, Vector3f position, Vector3f motion, Vector3f rotation) {
|
||||||
|
@ -46,11 +49,22 @@ public class TameableEntity extends AnimalEntity {
|
||||||
metadata.getFlags().setFlag(EntityFlag.SITTING, (xd & 0x01) == 0x01);
|
metadata.getFlags().setFlag(EntityFlag.SITTING, (xd & 0x01) == 0x01);
|
||||||
metadata.getFlags().setFlag(EntityFlag.ANGRY, (xd & 0x02) == 0x02);
|
metadata.getFlags().setFlag(EntityFlag.ANGRY, (xd & 0x02) == 0x02);
|
||||||
metadata.getFlags().setFlag(EntityFlag.TAMED, (xd & 0x04) == 0x04);
|
metadata.getFlags().setFlag(EntityFlag.TAMED, (xd & 0x04) == 0x04);
|
||||||
// Must be set for wolf collar color to work
|
}
|
||||||
// Extending it to all entities to prevent future bugs
|
|
||||||
if (metadata.getFlags().getFlag(EntityFlag.TAMED)) {
|
// Note: Must be set for wolf collar color to work
|
||||||
metadata.put(EntityData.OWNER_EID, session.getPlayerEntity().getGeyserId());
|
if (entityMetadata.getId() == 17) {
|
||||||
} // Can't de-tame an entity so no resetting the owner ID
|
if (entityMetadata.getValue() != null) {
|
||||||
|
// Owner UUID of entity
|
||||||
|
Entity entity = session.getEntityCache().getPlayerEntity((UUID) entityMetadata.getValue());
|
||||||
|
// Used as both a check since the player isn't in the entity cache and a normal fallback
|
||||||
|
if (entity == null) {
|
||||||
|
entity = session.getPlayerEntity();
|
||||||
|
}
|
||||||
|
// Translate to entity ID
|
||||||
|
metadata.put(EntityData.OWNER_EID, entity.getGeyserId());
|
||||||
|
} else {
|
||||||
|
metadata.put(EntityData.OWNER_EID, 0L); // Reset
|
||||||
|
}
|
||||||
}
|
}
|
||||||
super.updateBedrockMetadata(entityMetadata, session);
|
super.updateBedrockMetadata(entityMetadata, session);
|
||||||
}
|
}
|
||||||
|
|
|
@ -60,6 +60,11 @@ public class WolfEntity extends TameableEntity {
|
||||||
// Relies on EntityData.OWNER_EID being set in TameableEntity.java
|
// Relies on EntityData.OWNER_EID being set in TameableEntity.java
|
||||||
if (entityMetadata.getId() == 19 && !metadata.getFlags().getFlag(EntityFlag.ANGRY)) {
|
if (entityMetadata.getId() == 19 && !metadata.getFlags().getFlag(EntityFlag.ANGRY)) {
|
||||||
metadata.put(EntityData.COLOR, collarColor = (byte) (int) entityMetadata.getValue());
|
metadata.put(EntityData.COLOR, collarColor = (byte) (int) entityMetadata.getValue());
|
||||||
|
if (!metadata.containsKey(EntityData.OWNER_EID)) {
|
||||||
|
// If a color is set and there is no owner entity ID, set one.
|
||||||
|
// Otherwise, the entire wolf is set to that color: https://user-images.githubusercontent.com/9083212/99209989-92691200-2792-11eb-911d-9a315c955be9.png
|
||||||
|
metadata.put(EntityData.OWNER_EID, session.getPlayerEntity().getGeyserId());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Wolf anger (1.16+)
|
// Wolf anger (1.16+)
|
||||||
|
|
|
@ -26,26 +26,32 @@
|
||||||
package org.geysermc.connector.entity.living.merchant;
|
package org.geysermc.connector.entity.living.merchant;
|
||||||
|
|
||||||
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.VillagerData;
|
|
||||||
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.metadata.VillagerData;
|
||||||
import com.nukkitx.math.vector.Vector3f;
|
import com.nukkitx.math.vector.Vector3f;
|
||||||
|
import com.nukkitx.math.vector.Vector3i;
|
||||||
import com.nukkitx.protocol.bedrock.data.entity.EntityData;
|
import com.nukkitx.protocol.bedrock.data.entity.EntityData;
|
||||||
import com.nukkitx.protocol.bedrock.data.entity.EntityFlag;
|
import com.nukkitx.protocol.bedrock.data.entity.EntityFlag;
|
||||||
import com.nukkitx.protocol.bedrock.data.entity.EntityFlags;
|
import com.nukkitx.protocol.bedrock.packet.MoveEntityAbsolutePacket;
|
||||||
import com.nukkitx.protocol.bedrock.packet.*;
|
|
||||||
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;
|
||||||
import org.geysermc.connector.network.session.GeyserSession;
|
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.connector.network.translators.world.block.BlockTranslator;
|
||||||
|
|
||||||
import java.util.regex.Matcher;
|
import java.util.regex.Matcher;
|
||||||
import java.util.regex.Pattern;
|
import java.util.regex.Pattern;
|
||||||
|
|
||||||
public class VillagerEntity extends AbstractMerchantEntity {
|
public class VillagerEntity extends AbstractMerchantEntity {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A map of Java profession IDs to Bedrock IDs
|
||||||
|
*/
|
||||||
private static final Int2IntMap VILLAGER_VARIANTS = new Int2IntOpenHashMap();
|
private static final Int2IntMap VILLAGER_VARIANTS = new Int2IntOpenHashMap();
|
||||||
private static final Int2IntMap VILLAGER_REGIONS = new Int2IntOpenHashMap();
|
/**
|
||||||
|
* A map of all Java region IDs (plains, savanna...) to Bedrock
|
||||||
|
*/
|
||||||
|
public static final Int2IntMap VILLAGER_REGIONS = new Int2IntOpenHashMap();
|
||||||
|
|
||||||
static {
|
static {
|
||||||
// Java villager profession IDs -> Bedrock
|
// Java villager profession IDs -> Bedrock
|
||||||
|
@ -99,9 +105,9 @@ public class VillagerEntity extends AbstractMerchantEntity {
|
||||||
int bedId = 0;
|
int bedId = 0;
|
||||||
float bedPositionSubtractorW = 0;
|
float bedPositionSubtractorW = 0;
|
||||||
float bedPositionSubtractorN = 0;
|
float bedPositionSubtractorN = 0;
|
||||||
if (session.getConnector().getConfig().isCacheChunks()) {
|
Vector3i bedPosition = metadata.getPos(EntityData.BED_POSITION);
|
||||||
Position bedLocation = new Position((int) position.getFloorX(), (int) position.getFloorY(), (int) position.getFloorZ());
|
if (session.getConnector().getConfig().isCacheChunks() && bedPosition != null) {
|
||||||
bedId = session.getConnector().getWorldManager().getBlockAt(session, bedLocation);
|
bedId = session.getConnector().getWorldManager().getBlockAt(session, bedPosition);
|
||||||
}
|
}
|
||||||
String bedRotationZ = BlockTranslator.getJavaIdBlockMap().inverse().get(bedId);
|
String bedRotationZ = BlockTranslator.getJavaIdBlockMap().inverse().get(bedId);
|
||||||
setRotation(rotation);
|
setRotation(rotation);
|
||||||
|
|
|
@ -1,11 +1,25 @@
|
||||||
package org.geysermc.connector.entity.living.monster;
|
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.math.vector.Vector3f;
|
||||||
|
import com.nukkitx.protocol.bedrock.data.entity.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.utils.DimensionUtils;
|
||||||
|
|
||||||
public class BasePiglinEntity extends MonsterEntity {
|
public class BasePiglinEntity extends MonsterEntity {
|
||||||
|
|
||||||
public BasePiglinEntity(long entityId, long geyserId, EntityType entityType, Vector3f position, Vector3f motion, Vector3f rotation) {
|
public BasePiglinEntity(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) {
|
||||||
|
if (entityMetadata.getId() == 15) {
|
||||||
|
// Immune to zombification?
|
||||||
|
// Apply shaking effect if not in the nether and zombification is possible
|
||||||
|
metadata.getFlags().setFlag(EntityFlag.SHAKING, !((boolean) entityMetadata.getValue()) && !session.getDimension().equals(DimensionUtils.NETHER));
|
||||||
|
}
|
||||||
|
super.updateBedrockMetadata(entityMetadata, session);
|
||||||
|
}
|
||||||
}
|
}
|
|
@ -33,6 +33,12 @@ import org.geysermc.connector.network.session.GeyserSession;
|
||||||
|
|
||||||
public class CreeperEntity extends MonsterEntity {
|
public class CreeperEntity extends MonsterEntity {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Whether the creeper has been ignited and is using ID 17.
|
||||||
|
* In this instance we ignore ID 15 since it's sending us -1 which confuses poor Bedrock.
|
||||||
|
*/
|
||||||
|
private boolean ignitedByFlintAndSteel = false;
|
||||||
|
|
||||||
public CreeperEntity(long entityId, long geyserId, EntityType entityType, Vector3f position, Vector3f motion, Vector3f rotation) {
|
public CreeperEntity(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);
|
||||||
}
|
}
|
||||||
|
@ -40,13 +46,16 @@ 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) {
|
if (entityMetadata.getId() == 15) {
|
||||||
|
if (!ignitedByFlintAndSteel) {
|
||||||
metadata.getFlags().setFlag(EntityFlag.IGNITED, (int) entityMetadata.getValue() == 1);
|
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());
|
||||||
}
|
}
|
||||||
if (entityMetadata.getId() == 17) {
|
if (entityMetadata.getId() == 17) {
|
||||||
metadata.getFlags().setFlag(EntityFlag.IGNITED, (boolean) entityMetadata.getValue());
|
ignitedByFlintAndSteel = (boolean) entityMetadata.getValue();
|
||||||
|
metadata.getFlags().setFlag(EntityFlag.IGNITED, ignitedByFlintAndSteel);
|
||||||
}
|
}
|
||||||
|
|
||||||
super.updateBedrockMetadata(entityMetadata, session);
|
super.updateBedrockMetadata(entityMetadata, session);
|
||||||
|
|
|
@ -32,33 +32,60 @@ import com.nukkitx.protocol.bedrock.data.entity.EntityEventType;
|
||||||
import com.nukkitx.protocol.bedrock.data.entity.EntityFlag;
|
import com.nukkitx.protocol.bedrock.data.entity.EntityFlag;
|
||||||
import com.nukkitx.protocol.bedrock.packet.AddEntityPacket;
|
import com.nukkitx.protocol.bedrock.packet.AddEntityPacket;
|
||||||
import com.nukkitx.protocol.bedrock.packet.EntityEventPacket;
|
import com.nukkitx.protocol.bedrock.packet.EntityEventPacket;
|
||||||
|
import lombok.Data;
|
||||||
import org.geysermc.connector.entity.living.InsentientEntity;
|
import org.geysermc.connector.entity.living.InsentientEntity;
|
||||||
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 java.util.concurrent.ScheduledFuture;
|
||||||
|
import java.util.concurrent.TimeUnit;
|
||||||
|
|
||||||
public class EnderDragonEntity extends InsentientEntity {
|
public class EnderDragonEntity extends InsentientEntity {
|
||||||
|
/**
|
||||||
|
* The Ender Dragon has multiple hit boxes, which
|
||||||
|
* are each its own invisible entity
|
||||||
|
*/
|
||||||
|
private EnderDragonPartEntity head;
|
||||||
|
private EnderDragonPartEntity neck;
|
||||||
|
private EnderDragonPartEntity body;
|
||||||
|
private EnderDragonPartEntity leftWing;
|
||||||
|
private EnderDragonPartEntity rightWing;
|
||||||
|
private EnderDragonPartEntity[] tail;
|
||||||
|
|
||||||
|
private EnderDragonPartEntity[] allParts;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A circular buffer that stores a history of
|
||||||
|
* y and yaw values.
|
||||||
|
*/
|
||||||
|
private final Segment[] segmentHistory = new Segment[19];
|
||||||
|
private int latestSegment = -1;
|
||||||
|
|
||||||
|
private boolean hovering;
|
||||||
|
|
||||||
|
private ScheduledFuture<?> partPositionUpdater;
|
||||||
|
|
||||||
public EnderDragonEntity(long entityId, long geyserId, EntityType entityType, Vector3f position, Vector3f motion, Vector3f rotation) {
|
public EnderDragonEntity(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.getFlags().setFlag(EntityFlag.FIRE_IMMUNE, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void updateBedrockMetadata(EntityMetadata entityMetadata, GeyserSession session) {
|
public void updateBedrockMetadata(EntityMetadata entityMetadata, GeyserSession session) {
|
||||||
|
// Phase
|
||||||
if (entityMetadata.getId() == 15) {
|
if (entityMetadata.getId() == 15) {
|
||||||
metadata.getFlags().setFlag(EntityFlag.FIRE_IMMUNE, true);
|
int value = (int) entityMetadata.getValue();
|
||||||
switch ((int) entityMetadata.getValue()) {
|
if (value == 5) {
|
||||||
// Performing breath attack
|
// Performing breath attack
|
||||||
case 5:
|
|
||||||
EntityEventPacket entityEventPacket = new EntityEventPacket();
|
EntityEventPacket entityEventPacket = new EntityEventPacket();
|
||||||
entityEventPacket.setType(EntityEventType.DRAGON_FLAMING);
|
entityEventPacket.setType(EntityEventType.DRAGON_FLAMING);
|
||||||
entityEventPacket.setRuntimeEntityId(geyserId);
|
entityEventPacket.setRuntimeEntityId(geyserId);
|
||||||
entityEventPacket.setData(0);
|
entityEventPacket.setData(0);
|
||||||
session.sendUpstreamPacket(entityEventPacket);
|
session.sendUpstreamPacket(entityEventPacket);
|
||||||
case 6:
|
|
||||||
case 7:
|
|
||||||
metadata.getFlags().setFlag(EntityFlag.SITTING, true);
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
|
metadata.getFlags().setFlag(EntityFlag.SITTING, value == 5 || value == 6 || value == 7);
|
||||||
|
hovering = value == 10;
|
||||||
}
|
}
|
||||||
super.updateBedrockMetadata(entityMetadata, session);
|
super.updateBedrockMetadata(entityMetadata, session);
|
||||||
}
|
}
|
||||||
|
@ -81,6 +108,118 @@ public class EnderDragonEntity extends InsentientEntity {
|
||||||
valid = true;
|
valid = true;
|
||||||
session.sendUpstreamPacket(addEntityPacket);
|
session.sendUpstreamPacket(addEntityPacket);
|
||||||
|
|
||||||
|
head = new EnderDragonPartEntity(entityId + 1, session.getEntityCache().getNextEntityId().incrementAndGet(), EntityType.ENDER_DRAGON_PART, position, motion, rotation, 1, 1);
|
||||||
|
neck = new EnderDragonPartEntity(entityId + 2, session.getEntityCache().getNextEntityId().incrementAndGet(), EntityType.ENDER_DRAGON_PART, position, motion, rotation, 3, 3);
|
||||||
|
body = new EnderDragonPartEntity(entityId + 3, session.getEntityCache().getNextEntityId().incrementAndGet(), EntityType.ENDER_DRAGON_PART, position, motion, rotation, 5, 3);
|
||||||
|
leftWing = new EnderDragonPartEntity(entityId + 4, session.getEntityCache().getNextEntityId().incrementAndGet(), EntityType.ENDER_DRAGON_PART, position, motion, rotation, 4, 2);
|
||||||
|
rightWing = new EnderDragonPartEntity(entityId + 5, session.getEntityCache().getNextEntityId().incrementAndGet(), EntityType.ENDER_DRAGON_PART, position, motion, rotation, 4, 2);
|
||||||
|
tail = new EnderDragonPartEntity[3];
|
||||||
|
for (int i = 0; i < 3; i++) {
|
||||||
|
tail[i] = new EnderDragonPartEntity(entityId + 6 + i, session.getEntityCache().getNextEntityId().incrementAndGet(), EntityType.ENDER_DRAGON_PART, position, motion, rotation, 2, 2);
|
||||||
|
}
|
||||||
|
|
||||||
|
allParts = new EnderDragonPartEntity[]{head, neck, body, leftWing, rightWing, tail[0], tail[1], tail[2]};
|
||||||
|
|
||||||
|
for (EnderDragonPartEntity part : allParts) {
|
||||||
|
session.getEntityCache().spawnEntity(part);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int i = 0; i < segmentHistory.length; i++) {
|
||||||
|
segmentHistory[i] = new Segment();
|
||||||
|
segmentHistory[i].yaw = rotation.getZ();
|
||||||
|
segmentHistory[i].y = position.getY();
|
||||||
|
}
|
||||||
|
|
||||||
|
partPositionUpdater = session.getConnector().getGeneralThreadPool().scheduleAtFixedRate(() -> {
|
||||||
|
pushSegment();
|
||||||
|
updateBoundingBoxes(session);
|
||||||
|
}, 0, 50, TimeUnit.MILLISECONDS);
|
||||||
|
|
||||||
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 + ")");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean despawnEntity(GeyserSession session) {
|
||||||
|
partPositionUpdater.cancel(true);
|
||||||
|
|
||||||
|
for (EnderDragonPartEntity part : allParts) {
|
||||||
|
part.despawnEntity(session);
|
||||||
|
}
|
||||||
|
return super.despawnEntity(session);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Updates the positions of the Ender Dragon's multiple bounding boxes
|
||||||
|
*
|
||||||
|
* @param session GeyserSession.
|
||||||
|
*/
|
||||||
|
private void updateBoundingBoxes(GeyserSession session) {
|
||||||
|
Vector3f facingDir = Vector3f.createDirectionDeg(0, rotation.getZ());
|
||||||
|
Segment baseSegment = getSegment(5);
|
||||||
|
// Used to angle the head, neck, and tail when the dragon flies up/down
|
||||||
|
float pitch = (float) Math.toRadians(10 * (baseSegment.getY() - getSegment(10).getY()));
|
||||||
|
float pitchXZ = (float) Math.cos(pitch);
|
||||||
|
float pitchY = (float) Math.sin(pitch);
|
||||||
|
|
||||||
|
// Lowers the head when the dragon sits/hovers
|
||||||
|
float headDuck;
|
||||||
|
if (hovering || metadata.getFlags().getFlag(EntityFlag.SITTING)) {
|
||||||
|
headDuck = -1f;
|
||||||
|
} else {
|
||||||
|
headDuck = baseSegment.y - getSegment(0).y;
|
||||||
|
}
|
||||||
|
|
||||||
|
head.setPosition(facingDir.up(pitchY).mul(pitchXZ, 1, -pitchXZ).mul(6.5f).up(headDuck));
|
||||||
|
neck.setPosition(facingDir.up(pitchY).mul(pitchXZ, 1, -pitchXZ).mul(5.5f).up(headDuck));
|
||||||
|
body.setPosition(facingDir.mul(0.5f, 0f, -0.5f));
|
||||||
|
|
||||||
|
Vector3f wingPos = Vector3f.createDirectionDeg(0, 90f - rotation.getZ()).mul(4.5f).up(2f);
|
||||||
|
rightWing.setPosition(wingPos);
|
||||||
|
leftWing.setPosition(wingPos.mul(-1, 1, -1)); // Mirror horizontally
|
||||||
|
|
||||||
|
Vector3f tailBase = facingDir.mul(1.5f);
|
||||||
|
for (int i = 0; i < tail.length; i++) {
|
||||||
|
float distance = (i + 1) * 2f;
|
||||||
|
// Curls the tail when the dragon turns
|
||||||
|
Segment targetSegment = getSegment(12 + 2 * i);
|
||||||
|
float angle = rotation.getZ() + targetSegment.yaw - baseSegment.yaw;
|
||||||
|
|
||||||
|
float tailYOffset = targetSegment.y - baseSegment.y - (distance + 1.5f) * pitchY + 1.5f;
|
||||||
|
tail[i].setPosition(Vector3f.createDirectionDeg(0, angle).mul(distance).add(tailBase).mul(-pitchXZ, 1, pitchXZ).up(tailYOffset));
|
||||||
|
}
|
||||||
|
// Send updated positions
|
||||||
|
for (EnderDragonPartEntity part : allParts) {
|
||||||
|
part.moveAbsolute(session, part.getPosition().add(position), Vector3f.ZERO, false, false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Store the current yaw and y into the circular buffer
|
||||||
|
*/
|
||||||
|
private void pushSegment() {
|
||||||
|
latestSegment = (latestSegment + 1) % segmentHistory.length;
|
||||||
|
segmentHistory[latestSegment].yaw = rotation.getZ();
|
||||||
|
segmentHistory[latestSegment].y = position.getY();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the previous yaw and y
|
||||||
|
* Used to curl the tail and pitch the head and tail up/down
|
||||||
|
*
|
||||||
|
* @param index Number of ticks in the past
|
||||||
|
* @return Segment with the yaw and y
|
||||||
|
*/
|
||||||
|
private Segment getSegment(int index) {
|
||||||
|
index = (latestSegment - index) % segmentHistory.length;
|
||||||
|
if (index < 0) {
|
||||||
|
index += segmentHistory.length;
|
||||||
|
}
|
||||||
|
return segmentHistory[index];
|
||||||
|
}
|
||||||
|
|
||||||
|
@Data
|
||||||
|
private static class Segment {
|
||||||
|
private float yaw;
|
||||||
|
private float y;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,42 @@
|
||||||
|
/*
|
||||||
|
* 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.entity.EntityData;
|
||||||
|
import com.nukkitx.protocol.bedrock.data.entity.EntityFlag;
|
||||||
|
import org.geysermc.connector.entity.Entity;
|
||||||
|
import org.geysermc.connector.entity.type.EntityType;
|
||||||
|
|
||||||
|
public class EnderDragonPartEntity extends Entity {
|
||||||
|
public EnderDragonPartEntity(long entityId, long geyserId, EntityType entityType, Vector3f position, Vector3f motion, Vector3f rotation, float width, float height) {
|
||||||
|
super(entityId, geyserId, entityType, position, motion, rotation);
|
||||||
|
|
||||||
|
metadata.put(EntityData.BOUNDING_BOX_WIDTH, width);
|
||||||
|
metadata.put(EntityData.BOUNDING_BOX_HEIGHT, height);
|
||||||
|
metadata.getFlags().setFlag(EntityFlag.INVISIBLE, true);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,49 @@
|
||||||
|
/*
|
||||||
|
* 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.entity.EntityData;
|
||||||
|
import org.geysermc.connector.entity.living.FlyingEntity;
|
||||||
|
import org.geysermc.connector.entity.type.EntityType;
|
||||||
|
import org.geysermc.connector.network.session.GeyserSession;
|
||||||
|
|
||||||
|
public class GhastEntity extends FlyingEntity {
|
||||||
|
|
||||||
|
public GhastEntity(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) {
|
||||||
|
// If the ghast is attacking
|
||||||
|
metadata.put(EntityData.CHARGE_AMOUNT, (byte) ((boolean) entityMetadata.getValue() ? 1 : 0));
|
||||||
|
}
|
||||||
|
super.updateBedrockMetadata(entityMetadata, session);
|
||||||
|
}
|
||||||
|
}
|
|
@ -41,7 +41,7 @@ public class PiglinEntity extends BasePiglinEntity {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void updateBedrockMetadata(EntityMetadata entityMetadata, GeyserSession session) {
|
public void updateBedrockMetadata(EntityMetadata entityMetadata, GeyserSession session) {
|
||||||
if (entityMetadata.getId() == 15) {
|
if (entityMetadata.getId() == 16) {
|
||||||
boolean isBaby = (boolean) entityMetadata.getValue();
|
boolean isBaby = (boolean) entityMetadata.getValue();
|
||||||
if (isBaby) {
|
if (isBaby) {
|
||||||
metadata.put(EntityData.SCALE, .55f);
|
metadata.put(EntityData.SCALE, .55f);
|
||||||
|
|
|
@ -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.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.entity.EntityData;
|
||||||
|
import org.geysermc.connector.entity.type.EntityType;
|
||||||
|
import org.geysermc.connector.network.session.GeyserSession;
|
||||||
|
|
||||||
|
public class VexEntity extends MonsterEntity {
|
||||||
|
|
||||||
|
public VexEntity(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) {
|
||||||
|
byte xd = (byte) entityMetadata.getValue();
|
||||||
|
// Set the target to the player to force the attack animation
|
||||||
|
// even if the player isn't the target as we dont get the target on Java
|
||||||
|
metadata.put(EntityData.TARGET_EID, (xd & 0x01) == 0x01 ? session.getPlayerEntity().getGeyserId() : 0);
|
||||||
|
}
|
||||||
|
super.updateBedrockMetadata(entityMetadata, session);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,56 @@
|
||||||
|
/*
|
||||||
|
* 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.github.steveice10.mc.protocol.data.game.entity.metadata.VillagerData;
|
||||||
|
import com.nukkitx.math.vector.Vector3f;
|
||||||
|
import com.nukkitx.protocol.bedrock.data.entity.EntityData;
|
||||||
|
import com.nukkitx.protocol.bedrock.data.entity.EntityFlag;
|
||||||
|
import org.geysermc.connector.entity.living.merchant.VillagerEntity;
|
||||||
|
import org.geysermc.connector.entity.type.EntityType;
|
||||||
|
import org.geysermc.connector.network.session.GeyserSession;
|
||||||
|
|
||||||
|
public class ZombieVillagerEntity extends ZombieEntity {
|
||||||
|
|
||||||
|
public ZombieVillagerEntity(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() == 18) {
|
||||||
|
metadata.getFlags().setFlag(EntityFlag.IS_TRANSFORMING, (boolean) entityMetadata.getValue());
|
||||||
|
metadata.getFlags().setFlag(EntityFlag.SHAKING, (boolean) entityMetadata.getValue());
|
||||||
|
}
|
||||||
|
if (entityMetadata.getId() == 19) {
|
||||||
|
VillagerData villagerData = (VillagerData) entityMetadata.getValue();
|
||||||
|
// Region - only one used on Bedrock
|
||||||
|
metadata.put(EntityData.MARK_VARIANT, VillagerEntity.VILLAGER_REGIONS.get(villagerData.getType()));
|
||||||
|
}
|
||||||
|
super.updateBedrockMetadata(entityMetadata, session);
|
||||||
|
}
|
||||||
|
}
|
|
@ -23,18 +23,18 @@
|
||||||
* @link https://github.com/GeyserMC/Geyser
|
* @link https://github.com/GeyserMC/Geyser
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package org.geysermc.connector.entity;
|
package org.geysermc.connector.entity.player;
|
||||||
|
|
||||||
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.metadata.EntityMetadata;
|
import com.github.steveice10.mc.protocol.data.game.entity.metadata.EntityMetadata;
|
||||||
import com.github.steveice10.mc.protocol.data.game.scoreboard.NameTagVisibility;
|
|
||||||
import com.github.steveice10.mc.protocol.data.message.TextMessage;
|
|
||||||
import com.github.steveice10.opennbt.tag.builtin.CompoundTag;
|
import com.github.steveice10.opennbt.tag.builtin.CompoundTag;
|
||||||
import com.nukkitx.math.vector.Vector3f;
|
import com.nukkitx.math.vector.Vector3f;
|
||||||
|
import com.nukkitx.math.vector.Vector3i;
|
||||||
import com.nukkitx.protocol.bedrock.data.AttributeData;
|
import com.nukkitx.protocol.bedrock.data.AttributeData;
|
||||||
import com.nukkitx.protocol.bedrock.data.PlayerPermission;
|
import com.nukkitx.protocol.bedrock.data.PlayerPermission;
|
||||||
import com.nukkitx.protocol.bedrock.data.command.CommandPermission;
|
import com.nukkitx.protocol.bedrock.data.command.CommandPermission;
|
||||||
import com.nukkitx.protocol.bedrock.data.entity.EntityData;
|
import com.nukkitx.protocol.bedrock.data.entity.EntityData;
|
||||||
|
import com.nukkitx.protocol.bedrock.data.entity.EntityFlag;
|
||||||
import com.nukkitx.protocol.bedrock.data.entity.EntityLinkData;
|
import com.nukkitx.protocol.bedrock.data.entity.EntityLinkData;
|
||||||
import com.nukkitx.protocol.bedrock.packet.AddPlayerPacket;
|
import com.nukkitx.protocol.bedrock.packet.AddPlayerPacket;
|
||||||
import com.nukkitx.protocol.bedrock.packet.MovePlayerPacket;
|
import com.nukkitx.protocol.bedrock.packet.MovePlayerPacket;
|
||||||
|
@ -42,15 +42,17 @@ import com.nukkitx.protocol.bedrock.packet.SetEntityLinkPacket;
|
||||||
import com.nukkitx.protocol.bedrock.packet.UpdateAttributesPacket;
|
import com.nukkitx.protocol.bedrock.packet.UpdateAttributesPacket;
|
||||||
import lombok.Getter;
|
import lombok.Getter;
|
||||||
import lombok.Setter;
|
import lombok.Setter;
|
||||||
|
import net.kyori.adventure.text.Component;
|
||||||
|
import org.geysermc.connector.entity.Entity;
|
||||||
|
import org.geysermc.connector.entity.LivingEntity;
|
||||||
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.animal.tameable.ParrotEntity;
|
import org.geysermc.connector.entity.living.animal.tameable.ParrotEntity;
|
||||||
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.session.cache.EntityEffectCache;
|
|
||||||
import org.geysermc.connector.scoreboard.Team;
|
import org.geysermc.connector.scoreboard.Team;
|
||||||
import org.geysermc.connector.utils.AttributeUtils;
|
import org.geysermc.connector.utils.AttributeUtils;
|
||||||
import org.geysermc.connector.utils.MessageUtils;
|
import org.geysermc.connector.network.translators.chat.MessageTranslator;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
@ -63,9 +65,7 @@ public class PlayerEntity extends LivingEntity {
|
||||||
private GameProfile profile;
|
private GameProfile profile;
|
||||||
private UUID uuid;
|
private UUID uuid;
|
||||||
private String username;
|
private String username;
|
||||||
private long lastSkinUpdate = -1;
|
|
||||||
private boolean playerList = true; // Player is in the player list
|
private boolean playerList = true; // Player is in the player list
|
||||||
private final EntityEffectCache effectCache;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Saves the parrot currently on the player's left shoulder; otherwise null
|
* Saves the parrot currently on the player's left shoulder; otherwise null
|
||||||
|
@ -82,14 +82,10 @@ public class PlayerEntity extends LivingEntity {
|
||||||
profile = gameProfile;
|
profile = gameProfile;
|
||||||
uuid = gameProfile.getId();
|
uuid = gameProfile.getId();
|
||||||
username = gameProfile.getName();
|
username = gameProfile.getName();
|
||||||
effectCache = new EntityEffectCache();
|
|
||||||
if (geyserId == 1) valid = true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void spawnEntity(GeyserSession session) {
|
public void spawnEntity(GeyserSession session) {
|
||||||
if (geyserId == 1) return;
|
|
||||||
|
|
||||||
AddPlayerPacket addPlayerPacket = new AddPlayerPacket();
|
AddPlayerPacket addPlayerPacket = new AddPlayerPacket();
|
||||||
addPlayerPacket.setUuid(uuid);
|
addPlayerPacket.setUuid(uuid);
|
||||||
addPlayerPacket.setUsername(username);
|
addPlayerPacket.setUsername(username);
|
||||||
|
@ -160,6 +156,10 @@ 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);
|
||||||
|
|
||||||
|
// If this is the player logged in through this Geyser session
|
||||||
|
if (geyserId == 1) {
|
||||||
|
session.getCollisionManager().updatePlayerBoundingBox(position);
|
||||||
|
}
|
||||||
setOnGround(isOnGround);
|
setOnGround(isOnGround);
|
||||||
|
|
||||||
MovePlayerPacket movePlayerPacket = new MovePlayerPacket();
|
MovePlayerPacket movePlayerPacket = new MovePlayerPacket();
|
||||||
|
@ -168,6 +168,17 @@ public class PlayerEntity extends LivingEntity {
|
||||||
movePlayerPacket.setRotation(getBedrockRotation());
|
movePlayerPacket.setRotation(getBedrockRotation());
|
||||||
movePlayerPacket.setOnGround(isOnGround);
|
movePlayerPacket.setOnGround(isOnGround);
|
||||||
movePlayerPacket.setMode(MovePlayerPacket.Mode.NORMAL);
|
movePlayerPacket.setMode(MovePlayerPacket.Mode.NORMAL);
|
||||||
|
// If the player is moved while sleeping, we have to adjust their y, so it appears
|
||||||
|
// correctly on Bedrock. This fixes GSit's lay.
|
||||||
|
if (metadata.getFlags().getFlag(EntityFlag.SLEEPING)) {
|
||||||
|
Vector3i bedPosition = metadata.getPos(EntityData.BED_POSITION);
|
||||||
|
if (bedPosition != null && (bedPosition.getY() == 0 || bedPosition.distanceSquared(position.toInt()) > 4)) {
|
||||||
|
// Force the player movement by using a teleport
|
||||||
|
movePlayerPacket.setPosition(Vector3f.from(position.getX(), position.getY() - entityType.getOffset() + 0.2f, position.getZ()));
|
||||||
|
movePlayerPacket.setMode(MovePlayerPacket.Mode.TELEPORT);
|
||||||
|
movePlayerPacket.setTeleportationCause(MovePlayerPacket.TeleportationCause.UNKNOWN);
|
||||||
|
}
|
||||||
|
}
|
||||||
session.sendUpstreamPacket(movePlayerPacket);
|
session.sendUpstreamPacket(movePlayerPacket);
|
||||||
if (leftParrot != null) {
|
if (leftParrot != null) {
|
||||||
leftParrot.moveRelative(session, relX, relY, relZ, rotation, true);
|
leftParrot.moveRelative(session, relX, relY, relZ, rotation, true);
|
||||||
|
@ -220,7 +231,18 @@ public class PlayerEntity extends LivingEntity {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void setPosition(Vector3f position) {
|
public void setPosition(Vector3f position) {
|
||||||
this.position = position.add(0, entityType.getOffset(), 0);
|
setPosition(position, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the player position and specify if the entity type's offset should be added. Set to false when the player
|
||||||
|
* sends us a move packet where the offset is already added
|
||||||
|
*
|
||||||
|
* @param position the new position of the Bedrock player
|
||||||
|
* @param includeOffset whether to include the offset
|
||||||
|
*/
|
||||||
|
public void setPosition(Vector3f position, boolean includeOffset) {
|
||||||
|
this.position = includeOffset ? position.add(0, entityType.getOffset(), 0) : position;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -229,24 +251,18 @@ public class PlayerEntity extends LivingEntity {
|
||||||
|
|
||||||
if (entityMetadata.getId() == 2) {
|
if (entityMetadata.getId() == 2) {
|
||||||
String username = this.username;
|
String username = this.username;
|
||||||
TextMessage name = (TextMessage) entityMetadata.getValue();
|
Component name = (Component) entityMetadata.getValue();
|
||||||
if (name != null) {
|
if (name != null) {
|
||||||
username = MessageUtils.getBedrockMessage(name);
|
username = MessageTranslator.convertMessage(name);
|
||||||
}
|
}
|
||||||
Team team = session.getWorldCache().getScoreboard().getTeamFor(username);
|
Team team = session.getWorldCache().getScoreboard().getTeamFor(username);
|
||||||
if (team != null) {
|
if (team != null) {
|
||||||
// Cover different visibility settings
|
String displayName = "";
|
||||||
if (team.getNameTagVisibility() == NameTagVisibility.NEVER) {
|
if (team.isVisibleFor(session.getPlayerEntity().getUsername())) {
|
||||||
metadata.put(EntityData.NAMETAG, "");
|
displayName = MessageTranslator.toChatColor(team.getColor()) + username;
|
||||||
} else if (team.getNameTagVisibility() == NameTagVisibility.HIDE_FOR_OTHER_TEAMS &&
|
displayName = team.getCurrentData().getDisplayName(displayName);
|
||||||
!team.getEntities().contains(session.getPlayerEntity().getUsername())) {
|
|
||||||
metadata.put(EntityData.NAMETAG, "");
|
|
||||||
} else if (team.getNameTagVisibility() == NameTagVisibility.HIDE_FOR_OWN_TEAM &&
|
|
||||||
team.getEntities().contains(session.getPlayerEntity().getUsername())) {
|
|
||||||
metadata.put(EntityData.NAMETAG, "");
|
|
||||||
} else {
|
|
||||||
metadata.put(EntityData.NAMETAG, team.getPrefix() + MessageUtils.toChatColor(team.getColor()) + username + team.getSuffix());
|
|
||||||
}
|
}
|
||||||
|
metadata.put(EntityData.NAMETAG, displayName);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,67 @@
|
||||||
|
/*
|
||||||
|
* 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.player;
|
||||||
|
|
||||||
|
import com.github.steveice10.mc.auth.data.GameProfile;
|
||||||
|
import com.nukkitx.math.vector.Vector3f;
|
||||||
|
import org.geysermc.connector.network.session.GeyserSession;
|
||||||
|
|
||||||
|
import java.util.UUID;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The entity class specifically for a {@link GeyserSession}'s player.
|
||||||
|
*/
|
||||||
|
public class SessionPlayerEntity extends PlayerEntity {
|
||||||
|
|
||||||
|
private final GeyserSession session;
|
||||||
|
|
||||||
|
public SessionPlayerEntity(GeyserSession session) {
|
||||||
|
super(new GameProfile(UUID.randomUUID(), "unknown"), 1, 1, Vector3f.ZERO, Vector3f.ZERO, Vector3f.ZERO);
|
||||||
|
|
||||||
|
valid = true;
|
||||||
|
this.session = session;
|
||||||
|
this.session.getCollisionManager().updatePlayerBoundingBox(position);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void spawnEntity(GeyserSession session) {
|
||||||
|
// Already logged in
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void moveAbsolute(GeyserSession session, Vector3f position, Vector3f rotation, boolean isOnGround, boolean teleported) {
|
||||||
|
session.getCollisionManager().updatePlayerBoundingBox(position);
|
||||||
|
super.moveAbsolute(session, position, rotation, isOnGround, teleported);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setPosition(Vector3f position) {
|
||||||
|
if (session != null) { // null during entity initialization
|
||||||
|
session.getCollisionManager().updatePlayerBoundingBox(position);
|
||||||
|
}
|
||||||
|
super.setPosition(position);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,68 @@
|
||||||
|
/*
|
||||||
|
* 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.player;
|
||||||
|
|
||||||
|
import com.github.steveice10.mc.auth.data.GameProfile;
|
||||||
|
import com.nukkitx.math.vector.Vector3f;
|
||||||
|
import com.nukkitx.math.vector.Vector3i;
|
||||||
|
import com.nukkitx.protocol.bedrock.data.entity.EntityData;
|
||||||
|
import com.nukkitx.protocol.bedrock.data.entity.EntityFlag;
|
||||||
|
import lombok.Getter;
|
||||||
|
import lombok.Setter;
|
||||||
|
import org.geysermc.connector.network.session.GeyserSession;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A wrapper to handle skulls more effectively - skulls have to be treated as entities since there are no
|
||||||
|
* custom player skulls in Bedrock.
|
||||||
|
*/
|
||||||
|
public class SkullPlayerEntity extends PlayerEntity {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Stores the block state that the skull is associated with. Used to determine if the block in the skull's position
|
||||||
|
* has changed
|
||||||
|
*/
|
||||||
|
@Getter
|
||||||
|
@Setter
|
||||||
|
private int blockState;
|
||||||
|
|
||||||
|
public SkullPlayerEntity(GameProfile gameProfile, long geyserId, Vector3f position, Vector3f rotation) {
|
||||||
|
super(gameProfile, 0, geyserId, position, Vector3f.ZERO, rotation);
|
||||||
|
setPlayerList(false);
|
||||||
|
|
||||||
|
//Set bounding box to almost nothing so the skull is able to be broken and not cause entity to cast a shadow
|
||||||
|
metadata.clear();
|
||||||
|
metadata.put(EntityData.SCALE, 1.08f);
|
||||||
|
metadata.put(EntityData.BOUNDING_BOX_HEIGHT, 0.001f);
|
||||||
|
metadata.put(EntityData.BOUNDING_BOX_WIDTH, 0.001f);
|
||||||
|
metadata.getOrCreateFlags().setFlag(EntityFlag.CAN_SHOW_NAME, false);
|
||||||
|
metadata.getFlags().setFlag(EntityFlag.INVISIBLE, true); // Until the skin is loaded
|
||||||
|
}
|
||||||
|
|
||||||
|
public void despawnEntity(GeyserSession session, Vector3i position) {
|
||||||
|
this.despawnEntity(session);
|
||||||
|
session.getSkullCache().remove(position, this);
|
||||||
|
}
|
||||||
|
}
|
|
@ -37,6 +37,7 @@ import org.geysermc.connector.entity.living.monster.raid.AbstractIllagerEntity;
|
||||||
import org.geysermc.connector.entity.living.monster.raid.PillagerEntity;
|
import org.geysermc.connector.entity.living.monster.raid.PillagerEntity;
|
||||||
import org.geysermc.connector.entity.living.monster.raid.RaidParticipantEntity;
|
import org.geysermc.connector.entity.living.monster.raid.RaidParticipantEntity;
|
||||||
import org.geysermc.connector.entity.living.monster.raid.SpellcasterIllagerEntity;
|
import org.geysermc.connector.entity.living.monster.raid.SpellcasterIllagerEntity;
|
||||||
|
import org.geysermc.connector.entity.player.PlayerEntity;
|
||||||
|
|
||||||
@Getter
|
@Getter
|
||||||
public enum EntityType {
|
public enum EntityType {
|
||||||
|
@ -47,12 +48,12 @@ public enum EntityType {
|
||||||
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, "minecraft:villager_v2"),
|
VILLAGER(VillagerEntity.class, 15, 1.8f, 0.6f, 0.6f, 1.62f, "minecraft:villager_v2"),
|
||||||
MOOSHROOM(AnimalEntity.class, 16, 1.4f, 0.9f),
|
MOOSHROOM(MooshroomEntity.class, 16, 1.4f, 0.9f),
|
||||||
SQUID(SquidEntity.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(BatEntity.class, 19, 0.9f, 0.5f),
|
||||||
IRON_GOLEM(GolemEntity.class, 20, 2.7f, 1.4f),
|
IRON_GOLEM(GolemEntity.class, 20, 2.7f, 1.4f),
|
||||||
SNOW_GOLEM(GolemEntity.class, 21, 1.9f, 0.7f),
|
SNOW_GOLEM(SnowGolemEntity.class, 21, 1.9f, 0.7f),
|
||||||
OCELOT(OcelotEntity.class, 22, 0.35f, 0.3f),
|
OCELOT(OcelotEntity.class, 22, 0.35f, 0.3f),
|
||||||
HORSE(HorseEntity.class, 23, 1.6f, 1.3965f),
|
HORSE(HorseEntity.class, 23, 1.6f, 1.3965f),
|
||||||
DONKEY(ChestedHorseEntity.class, 24, 1.6f, 1.3965f),
|
DONKEY(ChestedHorseEntity.class, 24, 1.6f, 1.3965f),
|
||||||
|
@ -74,10 +75,10 @@ public enum EntityType {
|
||||||
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(GhastEntity.class, 41, 4.0f),
|
||||||
MAGMA_CUBE(MagmaCubeEntity.class, 42, 0.51f),
|
MAGMA_CUBE(MagmaCubeEntity.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(ZombieVillagerEntity.class, 44, 1.8f, 0.6f, 0.6f, 1.62f, "minecraft:zombie_villager_v2"),
|
||||||
WITCH(RaidParticipantEntity.class, 45, 1.8f, 0.6f, 0.6f, 1.62f),
|
WITCH(RaidParticipantEntity.class, 45, 1.8f, 0.6f, 0.6f, 1.62f),
|
||||||
STRAY(AbstractSkeletonEntity.class, 46, 1.8f, 0.6f, 0.6f, 1.62f),
|
STRAY(AbstractSkeletonEntity.class, 46, 1.8f, 0.6f, 0.6f, 1.62f),
|
||||||
HUSK(ZombieEntity.class, 47, 1.8f, 0.6f, 0.6f, 1.62f),
|
HUSK(ZombieEntity.class, 47, 1.8f, 0.6f, 0.6f, 1.62f),
|
||||||
|
@ -86,7 +87,7 @@ public enum EntityType {
|
||||||
ELDER_GUARDIAN(ElderGuardianEntity.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(WitherEntity.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, 0f, 0f),
|
||||||
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),
|
||||||
AGENT(Entity.class, 56, 0f),
|
AGENT(Entity.class, 56, 0f),
|
||||||
|
@ -99,7 +100,7 @@ public enum EntityType {
|
||||||
ARMOR_STAND(ArmorStandEntity.class, 61, 1.975f, 0.5f),
|
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, 0.25f, 0.125f),
|
||||||
PRIMED_TNT(TNTEntity.class, 65, 0.98f, 0.98f, 0.98f, 0f, "minecraft:tnt"),
|
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),
|
||||||
|
@ -109,7 +110,7 @@ public enum EntityType {
|
||||||
END_CRYSTAL(EnderCrystalEntity.class, 71, 2.0f, 2.0f, 2.0f, 0f, "minecraft:ender_crystal"),
|
END_CRYSTAL(EnderCrystalEntity.class, 71, 2.0f, 2.0f, 2.0f, 0f, "minecraft:ender_crystal"),
|
||||||
FIREWORK_ROCKET(FireworkEntity.class, 72, 0.25f, 0.25f, 0.25f, 0f, "minecraft:fireworks_rocket"),
|
FIREWORK_ROCKET(FireworkEntity.class, 72, 0.25f, 0.25f, 0.25f, 0f, "minecraft:fireworks_rocket"),
|
||||||
TRIDENT(TridentEntity.class, 73, 0f, 0f, 0f, 0f, "minecraft:thrown_trident"),
|
TRIDENT(TridentEntity.class, 73, 0f, 0f, 0f, 0f, "minecraft:thrown_trident"),
|
||||||
TURTLE(AnimalEntity.class, 74, 0.4f, 1.2f),
|
TURTLE(TurtleEntity.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, 0.3125f),
|
SHULKER_BULLET(Entity.class, 76, 0.3125f),
|
||||||
FISHING_BOBBER(FishingHookEntity.class, 77, 0f, 0f, 0f, 0f, "minecraft:fishing_hook"),
|
FISHING_BOBBER(FishingHookEntity.class, 77, 0f, 0f, 0f, 0f, "minecraft:fishing_hook"),
|
||||||
|
@ -125,9 +126,9 @@ public enum EntityType {
|
||||||
THROWN_POTION(ThrowableEntity.class, 86, 0.25f, 0.25f, 0.25f, 0f, "minecraft:splash_potion"),
|
THROWN_POTION(ThrowableEntity.class, 86, 0.25f, 0.25f, 0.25f, 0f, "minecraft:splash_potion"),
|
||||||
THROWN_ENDERPEARL(ThrowableEntity.class, 87, 0.25f, 0.25f, 0.25f, 0f, "minecraft:ender_pearl"),
|
THROWN_ENDERPEARL(ThrowableEntity.class, 87, 0.25f, 0.25f, 0.25f, 0f, "minecraft:ender_pearl"),
|
||||||
LEASH_KNOT(LeashKnotEntity.class, 88, 0.5f, 0.375f),
|
LEASH_KNOT(LeashKnotEntity.class, 88, 0.5f, 0.375f),
|
||||||
WITHER_SKULL(Entity.class, 89, 0.3125f),
|
WITHER_SKULL(WitherSkullEntity.class, 89, 0.3125f),
|
||||||
BOAT(BoatEntity.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(WitherSkullEntity.class, 91, 0f),
|
||||||
LIGHTNING_BOLT(Entity.class, 93, 0f),
|
LIGHTNING_BOLT(Entity.class, 93, 0f),
|
||||||
SMALL_FIREBALL(ItemedFireballEntity.class, 94, 0.3125f),
|
SMALL_FIREBALL(ItemedFireballEntity.class, 94, 0.3125f),
|
||||||
AREA_EFFECT_CLOUD(AreaEffectCloudEntity.class, 95, 0.5f, 1.0f),
|
AREA_EFFECT_CLOUD(AreaEffectCloudEntity.class, 95, 0.5f, 1.0f),
|
||||||
|
@ -141,7 +142,7 @@ public enum EntityType {
|
||||||
LLAMA_SPIT(Entity.class, 102, 0.25f),
|
LLAMA_SPIT(Entity.class, 102, 0.25f),
|
||||||
EVOKER_FANGS(Entity.class, 103, 0.8f, 0.5f, 0.5f, 0f, "minecraft:evocation_fang"),
|
EVOKER_FANGS(Entity.class, 103, 0.8f, 0.5f, 0.5f, 0f, "minecraft:evocation_fang"),
|
||||||
EVOKER(SpellcasterIllagerEntity.class, 104, 1.95f, 0.6f, 0.6f, 0f, "minecraft:evocation_illager"),
|
EVOKER(SpellcasterIllagerEntity.class, 104, 1.95f, 0.6f, 0.6f, 0f, "minecraft:evocation_illager"),
|
||||||
VEX(MonsterEntity.class, 105, 0.8f, 0.4f),
|
VEX(VexEntity.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),
|
||||||
|
@ -153,7 +154,7 @@ public enum EntityType {
|
||||||
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),
|
||||||
STRIDER(StriderEntity.class, 125, 1.7f, 0.9f, 0f, 0f, "minecraft:strider"),
|
STRIDER(StriderEntity.class, 125, 1.7f, 0.9f, 0f, 0f, "minecraft:strider"),
|
||||||
HOGLIN(AnimalEntity.class, 124, 1.4f, 1.3965f, 1.3965f, 0f, "minecraft:hoglin"),
|
HOGLIN(HoglinEntity.class, 124, 1.4f, 1.3965f, 1.3965f, 0f, "minecraft:hoglin"),
|
||||||
ZOGLIN(ZoglinEntity.class, 126, 1.4f, 1.3965f, 1.3965f, 0f, "minecraft:zoglin"),
|
ZOGLIN(ZoglinEntity.class, 126, 1.4f, 1.3965f, 1.3965f, 0f, "minecraft:zoglin"),
|
||||||
PIGLIN(PiglinEntity.class, 123, 1.95f, 0.6f, 0.6f, 0f, "minecraft:piglin"),
|
PIGLIN(PiglinEntity.class, 123, 1.95f, 0.6f, 0.6f, 0f, "minecraft:piglin"),
|
||||||
PIGLIN_BRUTE(BasePiglinEntity.class, 127, 1.95f, 0.6f, 0.6f, 0f, "minecraft:piglin_brute"),
|
PIGLIN_BRUTE(BasePiglinEntity.class, 127, 1.95f, 0.6f, 0.6f, 0f, "minecraft:piglin_brute"),
|
||||||
|
@ -166,7 +167,12 @@ public enum EntityType {
|
||||||
/**
|
/**
|
||||||
* Not an entity in Bedrock, so we replace it with a Pillager
|
* 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");
|
ILLUSIONER(AbstractIllagerEntity.class, 114, 1.8f, 0.6f, 0.6f, 1.62f, "minecraft:pillager"),
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Not an entity in Bedrock, but used for the Ender Dragon's multiple hitboxes
|
||||||
|
*/
|
||||||
|
ENDER_DRAGON_PART(EnderDragonPartEntity.class, 32, 0, 0, 0, 0, "minecraft:armor_stand");
|
||||||
|
|
||||||
private static final EntityType[] VALUES = values();
|
private static final EntityType[] VALUES = values();
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,32 @@
|
||||||
|
/*
|
||||||
|
* 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.inventory;
|
||||||
|
|
||||||
|
public class AnvilContainer extends Container {
|
||||||
|
public AnvilContainer(String title, int id, int size, PlayerInventory playerInventory) {
|
||||||
|
super(title, id, size, playerInventory);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,40 @@
|
||||||
|
/*
|
||||||
|
* 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.inventory;
|
||||||
|
|
||||||
|
import lombok.Getter;
|
||||||
|
import lombok.Setter;
|
||||||
|
|
||||||
|
@Getter
|
||||||
|
@Setter
|
||||||
|
public class BeaconContainer extends Container {
|
||||||
|
private int primaryId;
|
||||||
|
private int secondaryId;
|
||||||
|
|
||||||
|
public BeaconContainer(String title, int id,int size, PlayerInventory playerInventory) {
|
||||||
|
super(title, id, size, playerInventory);
|
||||||
|
}
|
||||||
|
}
|
|
@ -25,7 +25,6 @@
|
||||||
|
|
||||||
package org.geysermc.connector.inventory;
|
package org.geysermc.connector.inventory;
|
||||||
|
|
||||||
import com.github.steveice10.mc.protocol.data.game.window.WindowType;
|
|
||||||
import lombok.Getter;
|
import lombok.Getter;
|
||||||
import lombok.NonNull;
|
import lombok.NonNull;
|
||||||
import org.geysermc.connector.network.translators.inventory.InventoryTranslator;
|
import org.geysermc.connector.network.translators.inventory.InventoryTranslator;
|
||||||
|
@ -38,8 +37,8 @@ public class Container extends Inventory {
|
||||||
private final PlayerInventory playerInventory;
|
private final PlayerInventory playerInventory;
|
||||||
private final int containerSize;
|
private final int containerSize;
|
||||||
|
|
||||||
public Container(String title, int id, WindowType windowType, int size, PlayerInventory playerInventory) {
|
public Container(String title, int id, int size, PlayerInventory playerInventory) {
|
||||||
super(title, id, windowType, size);
|
super(title, id, size);
|
||||||
this.playerInventory = playerInventory;
|
this.playerInventory = playerInventory;
|
||||||
this.containerSize = this.size + InventoryTranslator.PLAYER_INVENTORY_SIZE;
|
this.containerSize = this.size + InventoryTranslator.PLAYER_INVENTORY_SIZE;
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,52 @@
|
||||||
|
/*
|
||||||
|
* 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.inventory;
|
||||||
|
|
||||||
|
import com.nukkitx.protocol.bedrock.data.inventory.EnchantOptionData;
|
||||||
|
import lombok.Getter;
|
||||||
|
|
||||||
|
public class EnchantingContainer extends Container {
|
||||||
|
/**
|
||||||
|
* A cache of what Bedrock sees
|
||||||
|
*/
|
||||||
|
@Getter
|
||||||
|
private final EnchantOptionData[] enchantOptions;
|
||||||
|
/**
|
||||||
|
* A mutable cache of what the server sends us
|
||||||
|
*/
|
||||||
|
@Getter
|
||||||
|
private final GeyserEnchantOption[] geyserEnchantOptions;
|
||||||
|
|
||||||
|
public EnchantingContainer(String title, int id, int size, PlayerInventory playerInventory) {
|
||||||
|
super(title, id, size, playerInventory);
|
||||||
|
|
||||||
|
enchantOptions = new EnchantOptionData[3];
|
||||||
|
geyserEnchantOptions = new GeyserEnchantOption[3];
|
||||||
|
for (int i = 0; i < geyserEnchantOptions.length; i++) {
|
||||||
|
geyserEnchantOptions[i] = new GeyserEnchantOption(i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue