forked from GeyserMC/Geyser
Update to latest master
This commit is contained in:
commit
4c5d80e2e9
164 changed files with 5990 additions and 1496 deletions
|
@ -87,8 +87,28 @@ public class GeyserBukkitConfiguration implements GeyserConfiguration {
|
|||
}
|
||||
|
||||
@Override
|
||||
public boolean isPingPassthrough() {
|
||||
return config.getBoolean("ping-passthrough", false);
|
||||
public boolean isCommandSuggestions() {
|
||||
return config.getBoolean("command-suggestions", true);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isPassthroughMotd() {
|
||||
return config.getBoolean("passthrough-motd", false);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isPassthroughPlayerCounts() {
|
||||
return config.getBoolean("passthrough-player-counts", false);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isLegacyPingPassthrough() {
|
||||
return config.getBoolean("legacy-ping-passthrough", false);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getPingPassthroughInterval() {
|
||||
return config.getInt("ping-passthrough-interval", 3);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -111,6 +131,11 @@ public class GeyserBukkitConfiguration implements GeyserConfiguration {
|
|||
return config.getBoolean("allow-third-party-capes", true);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isAllowThirdPartyEars() {
|
||||
return config.getBoolean("allow-third-party-ears", false);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getDefaultLocale() {
|
||||
return config.getString("default-locale", "en_us");
|
||||
|
@ -126,6 +151,11 @@ public class GeyserBukkitConfiguration implements GeyserConfiguration {
|
|||
return true; // We override this as with Bukkit, we have direct access to the server implementation
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isAboveBedrockNetherBuilding() {
|
||||
return config.getBoolean("above-bedrock-nether-building", false);
|
||||
}
|
||||
|
||||
@Override
|
||||
public IMetricsInfo getMetrics() {
|
||||
return metricsInfo;
|
||||
|
@ -203,4 +233,9 @@ public class GeyserBukkitConfiguration implements GeyserConfiguration {
|
|||
return config.getString("metrics.uuid", "generateduuid");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getConfigVersion() {
|
||||
return config.getInt("config-version", 0);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,79 @@
|
|||
/*
|
||||
* Copyright (c) 2019-2020 GeyserMC. http://geysermc.org
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*
|
||||
* @author GeyserMC
|
||||
* @link https://github.com/GeyserMC/Geyser
|
||||
*
|
||||
*/
|
||||
|
||||
package org.geysermc.platform.bukkit;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.event.server.ServerListPingEvent;
|
||||
import org.bukkit.util.CachedServerIcon;
|
||||
import org.geysermc.common.ping.GeyserPingInfo;
|
||||
import org.geysermc.connector.ping.IGeyserPingPassthrough;
|
||||
|
||||
import java.net.InetAddress;
|
||||
import java.util.Collections;
|
||||
import java.util.Iterator;
|
||||
|
||||
@AllArgsConstructor
|
||||
public class GeyserBukkitPingPassthrough implements IGeyserPingPassthrough {
|
||||
|
||||
private final GeyserBukkitLogger logger;
|
||||
|
||||
@Override
|
||||
public GeyserPingInfo getPingInformation() {
|
||||
try {
|
||||
ServerListPingEvent event = new GeyserPingEvent(InetAddress.getLocalHost(), Bukkit.getMotd(), Bukkit.getOnlinePlayers().size(), Bukkit.getMaxPlayers());
|
||||
Bukkit.getPluginManager().callEvent(event);
|
||||
GeyserPingInfo geyserPingInfo = new GeyserPingInfo(event.getMotd(), event.getNumPlayers(), event.getMaxPlayers());
|
||||
Bukkit.getOnlinePlayers().forEach(player -> {
|
||||
geyserPingInfo.addPlayer(player.getName());
|
||||
});
|
||||
return geyserPingInfo;
|
||||
} catch (Exception e) {
|
||||
logger.debug("Error while getting Bukkit ping passthrough: " + e.toString());
|
||||
return new GeyserPingInfo(null, 0, 0);
|
||||
}
|
||||
}
|
||||
|
||||
// These methods are unimplemented on spigot api by default so we add stubs so plugins don't complain
|
||||
private static class GeyserPingEvent extends ServerListPingEvent {
|
||||
|
||||
public GeyserPingEvent(InetAddress address, String motd, int numPlayers, int maxPlayers) {
|
||||
super(address, motd, numPlayers, maxPlayers);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setServerIcon(CachedServerIcon icon) throws IllegalArgumentException, UnsupportedOperationException {
|
||||
}
|
||||
|
||||
@Override
|
||||
public Iterator<Player> iterator() throws UnsupportedOperationException {
|
||||
return Collections.EMPTY_LIST.iterator();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -28,10 +28,13 @@ package org.geysermc.platform.bukkit;
|
|||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.plugin.java.JavaPlugin;
|
||||
import org.geysermc.common.PlatformType;
|
||||
import org.geysermc.connector.GeyserConfiguration;
|
||||
import org.geysermc.connector.GeyserConnector;
|
||||
import org.geysermc.connector.bootstrap.GeyserBootstrap;
|
||||
import org.geysermc.connector.command.CommandManager;
|
||||
import org.geysermc.connector.network.translators.world.WorldManager;
|
||||
import org.geysermc.connector.ping.GeyserLegacyPingPassthrough;
|
||||
import org.geysermc.connector.ping.IGeyserPingPassthrough;
|
||||
import org.geysermc.platform.bukkit.command.GeyserBukkitCommandExecutor;
|
||||
import org.geysermc.platform.bukkit.command.GeyserBukkitCommandManager;
|
||||
import org.geysermc.platform.bukkit.world.GeyserBukkitBlockPlaceListener;
|
||||
|
@ -45,6 +48,7 @@ public class GeyserBukkitPlugin extends JavaPlugin implements GeyserBootstrap {
|
|||
private GeyserBukkitCommandManager geyserCommandManager;
|
||||
private GeyserBukkitConfiguration geyserConfig;
|
||||
private GeyserBukkitLogger geyserLogger;
|
||||
private IGeyserPingPassthrough geyserBukkitPingPassthrough;
|
||||
private GeyserBukkitBlockPlaceListener blockPlaceListener;
|
||||
private GeyserBukkitWorldManager geyserWorldManager;
|
||||
|
||||
|
@ -70,11 +74,18 @@ public class GeyserBukkitPlugin extends JavaPlugin implements GeyserBootstrap {
|
|||
saveConfig();
|
||||
|
||||
this.geyserLogger = new GeyserBukkitLogger(getLogger(), geyserConfig.isDebugMode());
|
||||
GeyserConfiguration.checkGeyserConfiguration(geyserConfig, geyserLogger);
|
||||
|
||||
geyserConfig.loadFloodgate(this);
|
||||
|
||||
this.connector = GeyserConnector.start(PlatformType.BUKKIT, this);
|
||||
|
||||
if (geyserConfig.isLegacyPingPassthrough()) {
|
||||
this.geyserBukkitPingPassthrough = GeyserLegacyPingPassthrough.init(connector);
|
||||
} else {
|
||||
this.geyserBukkitPingPassthrough = new GeyserBukkitPingPassthrough(geyserLogger);
|
||||
}
|
||||
|
||||
this.geyserCommandManager = new GeyserBukkitCommandManager(this, connector);
|
||||
|
||||
boolean isViaVersion = false;
|
||||
|
@ -120,6 +131,11 @@ public class GeyserBukkitPlugin extends JavaPlugin implements GeyserBootstrap {
|
|||
return this.geyserCommandManager;
|
||||
}
|
||||
|
||||
@Override
|
||||
public IGeyserPingPassthrough getGeyserPingPassthrough() {
|
||||
return geyserBukkitPingPassthrough;
|
||||
}
|
||||
|
||||
@Override
|
||||
public WorldManager getWorldManager() {
|
||||
return this.geyserWorldManager;
|
||||
|
|
|
@ -4,6 +4,7 @@ author: ${project.organization.name}
|
|||
website: ${project.organization.url}
|
||||
version: ${project.version}
|
||||
softdepend: ["ViaVersion"]
|
||||
api-version: 1.13
|
||||
commands:
|
||||
geyser:
|
||||
description: The main command for Geyser.
|
||||
|
|
|
@ -20,7 +20,7 @@
|
|||
<dependency>
|
||||
<groupId>net.md-5</groupId>
|
||||
<artifactId>bungeecord-api</artifactId>
|
||||
<version>1.14-SNAPSHOT</version>
|
||||
<version>1.15-SNAPSHOT</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
|
|
@ -86,8 +86,28 @@ public class GeyserBungeeConfiguration implements GeyserConfiguration {
|
|||
}
|
||||
|
||||
@Override
|
||||
public boolean isPingPassthrough() {
|
||||
return config.getBoolean("ping-passthrough", false);
|
||||
public boolean isCommandSuggestions() {
|
||||
return config.getBoolean("command-suggestions", true);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isPassthroughMotd() {
|
||||
return config.getBoolean("passthrough-motd", false);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isPassthroughPlayerCounts() {
|
||||
return config.getBoolean("passthrough-player-counts", false);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isLegacyPingPassthrough() {
|
||||
return config.getBoolean("legacy-ping-passthrough", false);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getPingPassthroughInterval() {
|
||||
return config.getInt("ping-passthrough-interval", 3);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -110,6 +130,11 @@ public class GeyserBungeeConfiguration implements GeyserConfiguration {
|
|||
return config.getBoolean("allow-third-party-capes", true);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isAllowThirdPartyEars() {
|
||||
return config.getBoolean("allow-third-party-ears", false);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getDefaultLocale() {
|
||||
return config.getString("default-locale", "en_us");
|
||||
|
@ -125,6 +150,11 @@ public class GeyserBungeeConfiguration implements GeyserConfiguration {
|
|||
return config.getBoolean("cache-chunks", false);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isAboveBedrockNetherBuilding() {
|
||||
return config.getBoolean("above-bedrock-nether-building", false);
|
||||
}
|
||||
|
||||
@Override
|
||||
public BungeeMetricsInfo getMetrics() {
|
||||
return metricsInfo;
|
||||
|
@ -202,4 +232,9 @@ public class GeyserBungeeConfiguration implements GeyserConfiguration {
|
|||
return config.getString("metrics.uuid", "generateduuid");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getConfigVersion() {
|
||||
return config.getInt("config-version", 0);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,180 @@
|
|||
/*
|
||||
* Copyright (c) 2019-2020 GeyserMC. http://geysermc.org
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*
|
||||
* @author GeyserMC
|
||||
* @link https://github.com/GeyserMC/Geyser
|
||||
*
|
||||
*/
|
||||
|
||||
package org.geysermc.platform.bungeecord;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import net.md_5.bungee.api.ProxyServer;
|
||||
import net.md_5.bungee.api.ServerPing;
|
||||
import net.md_5.bungee.api.chat.BaseComponent;
|
||||
import net.md_5.bungee.api.config.ListenerInfo;
|
||||
import net.md_5.bungee.api.connection.PendingConnection;
|
||||
import net.md_5.bungee.api.event.ProxyPingEvent;
|
||||
import net.md_5.bungee.api.plugin.Listener;
|
||||
import net.md_5.bungee.protocol.ProtocolConstants;
|
||||
import org.geysermc.common.ping.GeyserPingInfo;
|
||||
import org.geysermc.connector.ping.IGeyserPingPassthrough;
|
||||
|
||||
import java.net.Inet4Address;
|
||||
import java.net.InetSocketAddress;
|
||||
import java.net.SocketAddress;
|
||||
import java.util.Arrays;
|
||||
import java.util.UUID;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
|
||||
@AllArgsConstructor
|
||||
public class GeyserBungeePingPassthrough implements IGeyserPingPassthrough, Listener {
|
||||
|
||||
private static final GeyserPendingConnection PENDING_CONNECTION = new GeyserPendingConnection();
|
||||
|
||||
private final ProxyServer proxyServer;
|
||||
|
||||
@Override
|
||||
public GeyserPingInfo getPingInformation() {
|
||||
CompletableFuture<ProxyPingEvent> future = new CompletableFuture<>();
|
||||
proxyServer.getPluginManager().callEvent(new ProxyPingEvent(PENDING_CONNECTION, getPingInfo(), (event, throwable) -> {
|
||||
if (throwable != null) future.completeExceptionally(throwable);
|
||||
else future.complete(event);
|
||||
}));
|
||||
ProxyPingEvent event = future.join();
|
||||
GeyserPingInfo geyserPingInfo = new GeyserPingInfo(
|
||||
event.getResponse().getDescription(),
|
||||
event.getResponse().getPlayers().getOnline(),
|
||||
event.getResponse().getPlayers().getMax()
|
||||
);
|
||||
if (event.getResponse().getPlayers().getSample() != null) {
|
||||
Arrays.stream(event.getResponse().getPlayers().getSample()).forEach(proxiedPlayer -> {
|
||||
geyserPingInfo.addPlayer(proxiedPlayer.getName());
|
||||
});
|
||||
}
|
||||
return geyserPingInfo;
|
||||
}
|
||||
|
||||
// This is static so pending connection can use it
|
||||
private static ListenerInfo getDefaultListener() {
|
||||
return ProxyServer.getInstance().getConfig().getListeners().iterator().next();
|
||||
}
|
||||
|
||||
private ServerPing getPingInfo() {
|
||||
return new ServerPing(
|
||||
new ServerPing.Protocol(proxyServer.getName() + " " + proxyServer.getGameVersion(), ProtocolConstants.SUPPORTED_VERSION_IDS.get(ProtocolConstants.SUPPORTED_VERSION_IDS.size() - 1)),
|
||||
new ServerPing.Players(getDefaultListener().getMaxPlayers(), proxyServer.getOnlineCount(), null),
|
||||
getDefaultListener().getMotd(), proxyServer.getConfig().getFaviconObject()
|
||||
);
|
||||
}
|
||||
|
||||
private static class GeyserPendingConnection implements PendingConnection {
|
||||
|
||||
private static final UUID FAKE_UUID = UUID.nameUUIDFromBytes("geyser!internal".getBytes());
|
||||
private static final InetSocketAddress FAKE_REMOTE = new InetSocketAddress(Inet4Address.getLoopbackAddress(), 69);
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getVersion() {
|
||||
return ProtocolConstants.SUPPORTED_VERSION_IDS.get(ProtocolConstants.SUPPORTED_VERSION_IDS.size() - 1);
|
||||
}
|
||||
|
||||
@Override
|
||||
public InetSocketAddress getVirtualHost() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ListenerInfo getListener() {
|
||||
return getDefaultListener();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getUUID() {
|
||||
return FAKE_UUID.toString();
|
||||
}
|
||||
|
||||
@Override
|
||||
public UUID getUniqueId() {
|
||||
return FAKE_UUID;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setUniqueId(UUID uuid) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isOnlineMode() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setOnlineMode(boolean b) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isLegacy() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public InetSocketAddress getAddress() {
|
||||
return FAKE_REMOTE;
|
||||
}
|
||||
|
||||
@Override
|
||||
public SocketAddress getSocketAddress() {
|
||||
return getAddress();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void disconnect(String s) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void disconnect(BaseComponent... baseComponents) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void disconnect(BaseComponent baseComponent) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isConnected() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Unsafe unsafe() {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -31,9 +31,12 @@ import net.md_5.bungee.config.Configuration;
|
|||
import net.md_5.bungee.config.ConfigurationProvider;
|
||||
import net.md_5.bungee.config.YamlConfiguration;
|
||||
import org.geysermc.common.PlatformType;
|
||||
import org.geysermc.connector.GeyserConfiguration;
|
||||
import org.geysermc.connector.GeyserConnector;
|
||||
import org.geysermc.connector.bootstrap.GeyserBootstrap;
|
||||
import org.geysermc.connector.command.CommandManager;
|
||||
import org.geysermc.connector.ping.GeyserLegacyPingPassthrough;
|
||||
import org.geysermc.connector.ping.IGeyserPingPassthrough;
|
||||
import org.geysermc.platform.bungeecord.command.GeyserBungeeCommandExecutor;
|
||||
import org.geysermc.platform.bungeecord.command.GeyserBungeeCommandManager;
|
||||
|
||||
|
@ -50,6 +53,7 @@ public class GeyserBungeePlugin extends Plugin implements GeyserBootstrap {
|
|||
private GeyserBungeeCommandManager geyserCommandManager;
|
||||
private GeyserBungeeConfiguration geyserConfig;
|
||||
private GeyserBungeeLogger geyserLogger;
|
||||
private IGeyserPingPassthrough geyserBungeePingPassthrough;
|
||||
|
||||
private GeyserConnector connector;
|
||||
|
||||
|
@ -116,6 +120,7 @@ public class GeyserBungeePlugin extends Plugin implements GeyserBootstrap {
|
|||
}
|
||||
|
||||
this.geyserLogger = new GeyserBungeeLogger(getLogger(), geyserConfig.isDebugMode());
|
||||
GeyserConfiguration.checkGeyserConfiguration(geyserConfig, geyserLogger);
|
||||
|
||||
geyserConfig.loadFloodgate(this);
|
||||
|
||||
|
@ -123,6 +128,12 @@ public class GeyserBungeePlugin extends Plugin implements GeyserBootstrap {
|
|||
|
||||
this.geyserCommandManager = new GeyserBungeeCommandManager(connector);
|
||||
|
||||
if (geyserConfig.isLegacyPingPassthrough()) {
|
||||
this.geyserBungeePingPassthrough = GeyserLegacyPingPassthrough.init(connector);
|
||||
} else {
|
||||
this.geyserBungeePingPassthrough = new GeyserBungeePingPassthrough(getProxy());
|
||||
}
|
||||
|
||||
this.getProxy().getPluginManager().registerCommand(this, new GeyserBungeeCommandExecutor(connector));
|
||||
}
|
||||
|
||||
|
@ -145,4 +156,9 @@ public class GeyserBungeePlugin extends Plugin implements GeyserBootstrap {
|
|||
public CommandManager getGeyserCommandManager() {
|
||||
return this.geyserCommandManager;
|
||||
}
|
||||
|
||||
@Override
|
||||
public IGeyserPingPassthrough getGeyserPingPassthrough() {
|
||||
return geyserBungeePingPassthrough;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -80,8 +80,28 @@ public class GeyserSpongeConfiguration implements GeyserConfiguration {
|
|||
}
|
||||
|
||||
@Override
|
||||
public boolean isPingPassthrough() {
|
||||
return node.getNode("ping-passthrough").getBoolean(false);
|
||||
public boolean isCommandSuggestions() {
|
||||
return node.getNode("command-suggestions").getBoolean(true);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isPassthroughMotd() {
|
||||
return node.getNode("passthrough-motd").getBoolean(false);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isPassthroughPlayerCounts() {
|
||||
return node.getNode("passthrough-player-counts").getBoolean(false);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isLegacyPingPassthrough() {
|
||||
return node.getNode("legacy-ping-passthrough").getBoolean(false);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getPingPassthroughInterval() {
|
||||
return node.getNode("ping-passthrough-interval").getInt(3);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -104,6 +124,11 @@ public class GeyserSpongeConfiguration implements GeyserConfiguration {
|
|||
return node.getNode("allow-third-party-capes").getBoolean(true);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isAllowThirdPartyEars() {
|
||||
return node.getNode("allow-third-party-ears").getBoolean(false);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getDefaultLocale() {
|
||||
return node.getNode("default-locale").getString("en_us");
|
||||
|
@ -119,6 +144,11 @@ public class GeyserSpongeConfiguration implements GeyserConfiguration {
|
|||
return node.getNode("cache-chunks").getBoolean(false);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isAboveBedrockNetherBuilding() {
|
||||
return node.getNode("above-bedrock-nether-building").getBoolean(false);
|
||||
}
|
||||
|
||||
@Override
|
||||
public SpongeMetricsInfo getMetrics() {
|
||||
return metricsInfo;
|
||||
|
@ -202,4 +232,9 @@ public class GeyserSpongeConfiguration implements GeyserConfiguration {
|
|||
return node.getNode("metrics").getNode("uuid").getString("generateduuid");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getConfigVersion() {
|
||||
return node.getNode("config-version").getInt(0);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,99 @@
|
|||
/*
|
||||
* Copyright (c) 2019-2020 GeyserMC. http://geysermc.org
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*
|
||||
* @author GeyserMC
|
||||
* @link https://github.com/GeyserMC/Geyser
|
||||
*
|
||||
*/
|
||||
|
||||
package org.geysermc.platform.sponge;
|
||||
|
||||
import org.geysermc.common.ping.GeyserPingInfo;
|
||||
import org.geysermc.connector.ping.IGeyserPingPassthrough;
|
||||
import org.spongepowered.api.MinecraftVersion;
|
||||
import org.spongepowered.api.Sponge;
|
||||
import org.spongepowered.api.event.SpongeEventFactory;
|
||||
import org.spongepowered.api.event.cause.Cause;
|
||||
import org.spongepowered.api.event.cause.EventContext;
|
||||
import org.spongepowered.api.event.server.ClientPingServerEvent;
|
||||
import org.spongepowered.api.network.status.StatusClient;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
import java.net.Inet4Address;
|
||||
import java.net.InetSocketAddress;
|
||||
import java.util.Optional;
|
||||
|
||||
public class GeyserSpongePingPassthrough implements IGeyserPingPassthrough {
|
||||
|
||||
private static final GeyserStatusClient STATUS_CLIENT = new GeyserStatusClient();
|
||||
private static final Cause CAUSE = Cause.of(EventContext.empty(), Sponge.getServer());
|
||||
|
||||
private static Method SpongeStatusResponse_create;
|
||||
|
||||
@SuppressWarnings({"unchecked", "rawtypes"})
|
||||
@Override
|
||||
public GeyserPingInfo getPingInformation() {
|
||||
// come on Sponge, this is in commons, why not expose it :(
|
||||
ClientPingServerEvent event;
|
||||
try {
|
||||
if(SpongeStatusResponse_create == null) {
|
||||
Class SpongeStatusResponse = Class.forName("org.spongepowered.common.network.status.SpongeStatusResponse");
|
||||
Class MinecraftServer = Class.forName("net.minecraft.server.MinecraftServer");
|
||||
SpongeStatusResponse_create = SpongeStatusResponse.getDeclaredMethod("create", MinecraftServer);
|
||||
}
|
||||
|
||||
Object response = SpongeStatusResponse_create.invoke(null, Sponge.getServer());
|
||||
event = SpongeEventFactory.createClientPingServerEvent(CAUSE, STATUS_CLIENT, (ClientPingServerEvent.Response) response);
|
||||
} catch (ReflectiveOperationException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
Sponge.getEventManager().post(event);
|
||||
GeyserPingInfo geyserPingInfo = new GeyserPingInfo(
|
||||
event.getResponse().getDescription().toPlain(),
|
||||
event.getResponse().getPlayers().orElseThrow(IllegalStateException::new).getOnline(),
|
||||
event.getResponse().getPlayers().orElseThrow(IllegalStateException::new).getMax());
|
||||
event.getResponse().getPlayers().get().getProfiles().forEach(player -> {
|
||||
geyserPingInfo.addPlayer(player.getName().orElseThrow(IllegalStateException::new));
|
||||
});
|
||||
return geyserPingInfo;
|
||||
}
|
||||
|
||||
@SuppressWarnings("NullableProblems")
|
||||
private static class GeyserStatusClient implements StatusClient {
|
||||
|
||||
private static final InetSocketAddress FAKE_REMOTE = new InetSocketAddress(Inet4Address.getLoopbackAddress(), 69);
|
||||
|
||||
@Override
|
||||
public InetSocketAddress getAddress() {
|
||||
return FAKE_REMOTE;
|
||||
}
|
||||
|
||||
@Override
|
||||
public MinecraftVersion getVersion() {
|
||||
return Sponge.getPlatform().getMinecraftVersion();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Optional<InetSocketAddress> getVirtualHost() {
|
||||
return Optional.empty();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -30,9 +30,12 @@ import ninja.leaping.configurate.ConfigurationNode;
|
|||
import ninja.leaping.configurate.loader.ConfigurationLoader;
|
||||
import ninja.leaping.configurate.yaml.YAMLConfigurationLoader;
|
||||
import org.geysermc.common.PlatformType;
|
||||
import org.geysermc.connector.GeyserConfiguration;
|
||||
import org.geysermc.connector.GeyserConnector;
|
||||
import org.geysermc.connector.bootstrap.GeyserBootstrap;
|
||||
import org.geysermc.connector.command.CommandManager;
|
||||
import org.geysermc.connector.ping.GeyserLegacyPingPassthrough;
|
||||
import org.geysermc.connector.ping.IGeyserPingPassthrough;
|
||||
import org.geysermc.connector.utils.FileUtils;
|
||||
import org.geysermc.platform.sponge.command.GeyserSpongeCommandExecutor;
|
||||
import org.geysermc.platform.sponge.command.GeyserSpongeCommandManager;
|
||||
|
@ -62,6 +65,7 @@ public class GeyserSpongePlugin implements GeyserBootstrap {
|
|||
private GeyserSpongeCommandManager geyserCommandManager;
|
||||
private GeyserSpongeConfiguration geyserConfig;
|
||||
private GeyserSpongeLogger geyserLogger;
|
||||
private IGeyserPingPassthrough geyserSpongePingPassthrough;
|
||||
|
||||
private GeyserConnector connector;
|
||||
|
||||
|
@ -105,9 +109,16 @@ public class GeyserSpongePlugin implements GeyserBootstrap {
|
|||
}
|
||||
|
||||
this.geyserLogger = new GeyserSpongeLogger(logger, geyserConfig.isDebugMode());
|
||||
GeyserConfiguration.checkGeyserConfiguration(geyserConfig, geyserLogger);
|
||||
this.connector = GeyserConnector.start(PlatformType.SPONGE, this);
|
||||
this.geyserCommandManager = new GeyserSpongeCommandManager(Sponge.getCommandManager(), connector);
|
||||
|
||||
if (geyserConfig.isLegacyPingPassthrough()) {
|
||||
this.geyserSpongePingPassthrough = GeyserLegacyPingPassthrough.init(connector);
|
||||
} else {
|
||||
this.geyserSpongePingPassthrough = new GeyserSpongePingPassthrough();
|
||||
}
|
||||
|
||||
this.geyserCommandManager = new GeyserSpongeCommandManager(Sponge.getCommandManager(), connector);
|
||||
Sponge.getCommandManager().register(this, new GeyserSpongeCommandExecutor(connector), "geyser");
|
||||
}
|
||||
|
||||
|
@ -131,6 +142,11 @@ public class GeyserSpongePlugin implements GeyserBootstrap {
|
|||
return this.geyserCommandManager;
|
||||
}
|
||||
|
||||
@Override
|
||||
public IGeyserPingPassthrough getGeyserPingPassthrough() {
|
||||
return geyserSpongePingPassthrough;
|
||||
}
|
||||
|
||||
@Listener
|
||||
public void onServerStart(GameStartedServerEvent event) {
|
||||
onEnable();
|
||||
|
|
|
@ -26,10 +26,12 @@
|
|||
package org.geysermc.platform.standalone;
|
||||
|
||||
import org.geysermc.common.PlatformType;
|
||||
import org.geysermc.connector.ping.GeyserLegacyPingPassthrough;
|
||||
import org.geysermc.connector.GeyserConfiguration;
|
||||
import org.geysermc.connector.bootstrap.GeyserBootstrap;
|
||||
import org.geysermc.connector.GeyserConnector;
|
||||
import org.geysermc.connector.command.CommandManager;
|
||||
import org.geysermc.connector.ping.IGeyserPingPassthrough;
|
||||
import org.geysermc.connector.utils.FileUtils;
|
||||
import org.geysermc.platform.standalone.command.GeyserCommandManager;
|
||||
|
||||
|
@ -40,8 +42,9 @@ import java.util.UUID;
|
|||
public class GeyserStandaloneBootstrap implements GeyserBootstrap {
|
||||
|
||||
private GeyserCommandManager geyserCommandManager;
|
||||
private GeyserConfiguration geyserConfig;
|
||||
private GeyserStandaloneConfiguration geyserConfig;
|
||||
private GeyserStandaloneLogger geyserLogger;
|
||||
private IGeyserPingPassthrough geyserPingPassthrough;
|
||||
|
||||
private GeyserConnector connector;
|
||||
|
||||
|
@ -62,9 +65,13 @@ public class GeyserStandaloneBootstrap implements GeyserBootstrap {
|
|||
geyserLogger.severe("Failed to read/create config.yml! Make sure it's up to date and/or readable+writable!", ex);
|
||||
System.exit(0);
|
||||
}
|
||||
GeyserConfiguration.checkGeyserConfiguration(geyserConfig, geyserLogger);
|
||||
|
||||
connector = GeyserConnector.start(PlatformType.STANDALONE, this);
|
||||
geyserCommandManager = new GeyserCommandManager(connector);
|
||||
|
||||
geyserPingPassthrough = GeyserLegacyPingPassthrough.init(connector);
|
||||
|
||||
geyserLogger.start();
|
||||
}
|
||||
|
||||
|
@ -88,4 +95,9 @@ public class GeyserStandaloneBootstrap implements GeyserBootstrap {
|
|||
public CommandManager getGeyserCommandManager() {
|
||||
return geyserCommandManager;
|
||||
}
|
||||
|
||||
@Override
|
||||
public IGeyserPingPassthrough getGeyserPingPassthrough() {
|
||||
return geyserPingPassthrough;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -47,8 +47,20 @@ public class GeyserStandaloneConfiguration implements GeyserConfiguration {
|
|||
|
||||
private Map<String, UserAuthenticationInfo> userAuths;
|
||||
|
||||
@JsonProperty("ping-passthrough")
|
||||
private boolean pingPassthrough;
|
||||
@JsonProperty("command-suggestions")
|
||||
private boolean isCommandSuggestions;
|
||||
|
||||
@JsonProperty("passthrough-motd")
|
||||
private boolean isPassthroughMotd;
|
||||
|
||||
@JsonProperty("passthrough-player-counts")
|
||||
private boolean isPassthroughPlayerCounts;
|
||||
|
||||
@JsonProperty("legacy-ping-passthrough")
|
||||
private boolean isLegacyPingPassthrough;
|
||||
|
||||
@JsonProperty("ping-passthrough-interval")
|
||||
private int pingPassthroughInterval;
|
||||
|
||||
@JsonProperty("max-players")
|
||||
private int maxPlayers;
|
||||
|
@ -62,12 +74,18 @@ public class GeyserStandaloneConfiguration implements GeyserConfiguration {
|
|||
@JsonProperty("allow-third-party-capes")
|
||||
private boolean allowThirdPartyCapes;
|
||||
|
||||
@JsonProperty("allow-third-party-ears")
|
||||
private boolean allowThirdPartyEars;
|
||||
|
||||
@JsonProperty("default-locale")
|
||||
private String defaultLocale;
|
||||
|
||||
@JsonProperty("cache-chunks")
|
||||
private boolean cacheChunks;
|
||||
|
||||
@JsonProperty("above-bedrock-nether-building")
|
||||
private boolean isAboveBedrockNetherBuilding;
|
||||
|
||||
private MetricsInfo metrics;
|
||||
|
||||
@Override
|
||||
|
@ -112,4 +130,7 @@ public class GeyserStandaloneConfiguration implements GeyserConfiguration {
|
|||
@JsonProperty("uuid")
|
||||
private String uniqueId;
|
||||
}
|
||||
|
||||
@JsonProperty("config-version")
|
||||
private int configVersion;
|
||||
}
|
||||
|
|
|
@ -52,8 +52,20 @@ public class GeyserVelocityConfiguration implements GeyserConfiguration {
|
|||
|
||||
private Map<String, UserAuthenticationInfo> userAuths;
|
||||
|
||||
@JsonProperty("ping-passthrough")
|
||||
private boolean pingPassthrough;
|
||||
@JsonProperty("command-suggestions")
|
||||
private boolean commandSuggestions;
|
||||
|
||||
@JsonProperty("passthrough-motd")
|
||||
private boolean isPassthroughMotd;
|
||||
|
||||
@JsonProperty("passthrough-player-counts")
|
||||
private boolean isPassthroughPlayerCounts;
|
||||
|
||||
@JsonProperty("legacy-ping-passthrough")
|
||||
private boolean isLegacyPingPassthrough;
|
||||
|
||||
@JsonProperty("ping-passthrough-interval")
|
||||
private int pingPassthroughInterval;
|
||||
|
||||
@JsonProperty("max-players")
|
||||
private int maxPlayers;
|
||||
|
@ -67,12 +79,18 @@ public class GeyserVelocityConfiguration implements GeyserConfiguration {
|
|||
@JsonProperty("allow-third-party-capes")
|
||||
private boolean allowThirdPartyCapes;
|
||||
|
||||
@JsonProperty("allow-third-party-ears")
|
||||
private boolean allowThirdPartyEars;
|
||||
|
||||
@JsonProperty("default-locale")
|
||||
private String defaultLocale;
|
||||
|
||||
@JsonProperty("cache-chunks")
|
||||
private boolean cacheChunks;
|
||||
|
||||
@JsonProperty("above-bedrock-nether-building")
|
||||
private boolean aboveBedrockNetherBuilding;
|
||||
|
||||
private MetricsInfo metrics;
|
||||
|
||||
private Path floodgateKey;
|
||||
|
@ -127,4 +145,7 @@ public class GeyserVelocityConfiguration implements GeyserConfiguration {
|
|||
@JsonProperty("uuid")
|
||||
private String uniqueId;
|
||||
}
|
||||
|
||||
@JsonProperty("config-version")
|
||||
private int configVersion;
|
||||
}
|
||||
|
|
|
@ -0,0 +1,98 @@
|
|||
/*
|
||||
* Copyright (c) 2019-2020 GeyserMC. http://geysermc.org
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*
|
||||
* @author GeyserMC
|
||||
* @link https://github.com/GeyserMC/Geyser
|
||||
*
|
||||
*/
|
||||
|
||||
package org.geysermc.platform.velocity;
|
||||
|
||||
import com.velocitypowered.api.event.proxy.ProxyPingEvent;
|
||||
import com.velocitypowered.api.network.ProtocolVersion;
|
||||
import com.velocitypowered.api.proxy.InboundConnection;
|
||||
import com.velocitypowered.api.proxy.ProxyServer;
|
||||
import com.velocitypowered.api.proxy.server.ServerPing;
|
||||
import lombok.AllArgsConstructor;
|
||||
import net.kyori.text.TextComponent;
|
||||
import net.kyori.text.serializer.legacy.LegacyComponentSerializer;
|
||||
import org.geysermc.common.ping.GeyserPingInfo;
|
||||
import org.geysermc.connector.ping.IGeyserPingPassthrough;
|
||||
|
||||
import java.net.Inet4Address;
|
||||
import java.net.InetSocketAddress;
|
||||
import java.util.Optional;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
|
||||
@AllArgsConstructor
|
||||
public class GeyserVelocityPingPassthrough implements IGeyserPingPassthrough {
|
||||
|
||||
private static final GeyserInboundConnection FAKE_INBOUND_CONNECTION = new GeyserInboundConnection();
|
||||
|
||||
private final ProxyServer server;
|
||||
|
||||
@Override
|
||||
public GeyserPingInfo getPingInformation() {
|
||||
ProxyPingEvent event;
|
||||
try {
|
||||
event = server.getEventManager().fire(new ProxyPingEvent(FAKE_INBOUND_CONNECTION, ServerPing.builder()
|
||||
.description(server.getConfiguration().getMotdComponent()).onlinePlayers(server.getPlayerCount())
|
||||
.maximumPlayers(server.getConfiguration().getShowMaxPlayers()).build())).get();
|
||||
} catch (ExecutionException | InterruptedException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
GeyserPingInfo geyserPingInfo = new GeyserPingInfo(
|
||||
LegacyComponentSerializer.INSTANCE.serialize(event.getPing().getDescription(), '§'),
|
||||
event.getPing().getPlayers().orElseThrow(IllegalStateException::new).getOnline(),
|
||||
event.getPing().getPlayers().orElseThrow(IllegalStateException::new).getMax()
|
||||
);
|
||||
event.getPing().getPlayers().get().getSample().forEach(player -> {
|
||||
geyserPingInfo.addPlayer(player.getName());
|
||||
});
|
||||
return geyserPingInfo;
|
||||
}
|
||||
|
||||
private static class GeyserInboundConnection implements InboundConnection {
|
||||
|
||||
private static final InetSocketAddress FAKE_REMOTE = new InetSocketAddress(Inet4Address.getLoopbackAddress(), 69);
|
||||
|
||||
@Override
|
||||
public InetSocketAddress getRemoteAddress() {
|
||||
return FAKE_REMOTE;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Optional<InetSocketAddress> getVirtualHost() {
|
||||
return Optional.empty();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isActive() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ProtocolVersion getProtocolVersion() {
|
||||
return ProtocolVersion.MAXIMUM_VERSION;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -35,8 +35,11 @@ import com.velocitypowered.api.plugin.Plugin;
|
|||
|
||||
import com.velocitypowered.api.proxy.ProxyServer;
|
||||
import org.geysermc.common.PlatformType;
|
||||
import org.geysermc.connector.GeyserConfiguration;
|
||||
import org.geysermc.connector.GeyserConnector;
|
||||
import org.geysermc.connector.bootstrap.GeyserBootstrap;
|
||||
import org.geysermc.connector.ping.GeyserLegacyPingPassthrough;
|
||||
import org.geysermc.connector.ping.IGeyserPingPassthrough;
|
||||
import org.geysermc.connector.utils.FileUtils;
|
||||
import org.geysermc.platform.velocity.command.GeyserVelocityCommandExecutor;
|
||||
import org.geysermc.platform.velocity.command.GeyserVelocityCommandManager;
|
||||
|
@ -62,6 +65,7 @@ public class GeyserVelocityPlugin implements GeyserBootstrap {
|
|||
private GeyserVelocityCommandManager geyserCommandManager;
|
||||
private GeyserVelocityConfiguration geyserConfig;
|
||||
private GeyserVelocityLogger geyserLogger;
|
||||
private IGeyserPingPassthrough geyserPingPassthrough;
|
||||
|
||||
private GeyserConnector connector;
|
||||
|
||||
|
@ -90,6 +94,7 @@ public class GeyserVelocityPlugin implements GeyserBootstrap {
|
|||
geyserConfig.getRemote().setPort(javaAddr.getPort());
|
||||
|
||||
this.geyserLogger = new GeyserVelocityLogger(logger, geyserConfig.isDebugMode());
|
||||
GeyserConfiguration.checkGeyserConfiguration(geyserConfig, geyserLogger);
|
||||
|
||||
geyserConfig.loadFloodgate(this, proxyServer, configDir);
|
||||
|
||||
|
@ -97,6 +102,11 @@ public class GeyserVelocityPlugin implements GeyserBootstrap {
|
|||
|
||||
this.geyserCommandManager = new GeyserVelocityCommandManager(connector);
|
||||
this.commandManager.register(new GeyserVelocityCommandExecutor(connector), "geyser");
|
||||
if (geyserConfig.isLegacyPingPassthrough()) {
|
||||
this.geyserPingPassthrough = GeyserLegacyPingPassthrough.init(connector);
|
||||
} else {
|
||||
this.geyserPingPassthrough = new GeyserVelocityPingPassthrough(proxyServer);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -119,6 +129,11 @@ public class GeyserVelocityPlugin implements GeyserBootstrap {
|
|||
return this.geyserCommandManager;
|
||||
}
|
||||
|
||||
@Override
|
||||
public IGeyserPingPassthrough getGeyserPingPassthrough() {
|
||||
return geyserPingPassthrough;
|
||||
}
|
||||
|
||||
@Subscribe
|
||||
public void onInit(ProxyInitializeEvent event) {
|
||||
onEnable();
|
||||
|
|
|
@ -0,0 +1,48 @@
|
|||
/*
|
||||
* Copyright (c) 2019-2020 GeyserMC. http://geysermc.org
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*
|
||||
* @author GeyserMC
|
||||
* @link https://github.com/GeyserMC/Geyser
|
||||
*
|
||||
*/
|
||||
|
||||
package org.geysermc.common.ping;
|
||||
|
||||
import lombok.Data;
|
||||
import lombok.Getter;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
|
||||
@Data
|
||||
public class GeyserPingInfo {
|
||||
|
||||
public final String motd;
|
||||
public final int currentPlayerCount;
|
||||
public final int maxPlayerCount;
|
||||
|
||||
@Getter
|
||||
private Collection<String> players = new ArrayList<>();
|
||||
|
||||
public void addPlayer(String username) {
|
||||
players.add(username);
|
||||
}
|
||||
}
|
|
@ -98,14 +98,8 @@
|
|||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.github.steveice10</groupId>
|
||||
<artifactId>opennbt</artifactId>
|
||||
<version>1.4-SNAPSHOT</version>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.github.steveice10</groupId>
|
||||
<artifactId>packetlib</artifactId>
|
||||
<version>1.5-SNAPSHOT</version>
|
||||
<artifactId>mcprotocollib</artifactId>
|
||||
<version>4c315aa206</version>
|
||||
<scope>compile</scope>
|
||||
<exclusions>
|
||||
<exclusion>
|
||||
|
@ -115,31 +109,11 @@
|
|||
</exclusions>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.github.steveice10</groupId>
|
||||
<artifactId>mcauthlib</artifactId>
|
||||
<version>1.3-SNAPSHOT</version>
|
||||
<groupId>io.netty</groupId>
|
||||
<artifactId>netty-resolver-dns</artifactId>
|
||||
<version>4.1.43.Final</version>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.github.steveice10</groupId>
|
||||
<artifactId>mcprotocollib</artifactId>
|
||||
<version>1.15.2-1-SNAPSHOT</version>
|
||||
<scope>compile</scope>
|
||||
<exclusions>
|
||||
<exclusion>
|
||||
<groupId>com.github.steveice10</groupId>
|
||||
<artifactId>opennbt</artifactId>
|
||||
</exclusion>
|
||||
<exclusion>
|
||||
<groupId>com.github.steveice10</groupId>
|
||||
<artifactId>packetlib</artifactId>
|
||||
</exclusion>
|
||||
<exclusion>
|
||||
<groupId>com.github.steveice10</groupId>
|
||||
<artifactId>mcauthlib</artifactId>
|
||||
</exclusion>
|
||||
</exclusions>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.reflections</groupId>
|
||||
<artifactId>reflections</artifactId>
|
||||
|
|
|
@ -31,13 +31,24 @@ import java.util.Map;
|
|||
|
||||
public interface GeyserConfiguration {
|
||||
|
||||
// Modify this when you update the config
|
||||
int CURRENT_CONFIG_VERSION = 3;
|
||||
|
||||
IBedrockConfiguration getBedrock();
|
||||
|
||||
IRemoteConfiguration getRemote();
|
||||
|
||||
Map<String, ? extends IUserAuthenticationInfo> getUserAuths();
|
||||
|
||||
boolean isPingPassthrough();
|
||||
boolean isCommandSuggestions();
|
||||
|
||||
boolean isPassthroughMotd();
|
||||
|
||||
boolean isPassthroughPlayerCounts();
|
||||
|
||||
boolean isLegacyPingPassthrough();
|
||||
|
||||
int getPingPassthroughInterval();
|
||||
|
||||
int getMaxPlayers();
|
||||
|
||||
|
@ -47,10 +58,14 @@ public interface GeyserConfiguration {
|
|||
|
||||
boolean isAllowThirdPartyCapes();
|
||||
|
||||
boolean isAllowThirdPartyEars();
|
||||
|
||||
String getDefaultLocale();
|
||||
|
||||
Path getFloodgateKeyFile();
|
||||
|
||||
boolean isAboveBedrockNetherBuilding();
|
||||
|
||||
boolean isCacheChunks();
|
||||
|
||||
IMetricsInfo getMetrics();
|
||||
|
@ -87,4 +102,14 @@ public interface GeyserConfiguration {
|
|||
|
||||
String getUniqueId();
|
||||
}
|
||||
|
||||
int getConfigVersion();
|
||||
|
||||
static void checkGeyserConfiguration(GeyserConfiguration geyserConfig, GeyserLogger geyserLogger) {
|
||||
if (geyserConfig.getConfigVersion() < CURRENT_CONFIG_VERSION) {
|
||||
geyserLogger.warning("Your Geyser config is out of date! Please regenerate your config when possible.");
|
||||
} else if (geyserConfig.getConfigVersion() > CURRENT_CONFIG_VERSION) {
|
||||
geyserLogger.warning("Your Geyser config is too new! Errors may occur.");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -25,6 +25,8 @@
|
|||
|
||||
package org.geysermc.connector;
|
||||
|
||||
import com.fasterxml.jackson.databind.DeserializationFeature;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import com.nukkitx.protocol.bedrock.BedrockPacketCodec;
|
||||
import com.nukkitx.protocol.bedrock.BedrockServer;
|
||||
import com.nukkitx.protocol.bedrock.v390.Bedrock_v390;
|
||||
|
@ -37,10 +39,20 @@ import org.geysermc.connector.metrics.Metrics;
|
|||
import org.geysermc.connector.network.ConnectorServerEventHandler;
|
||||
import org.geysermc.connector.network.remote.RemoteServer;
|
||||
import org.geysermc.connector.network.session.GeyserSession;
|
||||
import org.geysermc.connector.network.translators.Translators;
|
||||
import org.geysermc.connector.network.translators.BiomeTranslator;
|
||||
import org.geysermc.connector.network.translators.EntityIdentifierRegistry;
|
||||
import org.geysermc.connector.network.translators.PacketTranslatorRegistry;
|
||||
import org.geysermc.connector.network.translators.item.ItemRegistry;
|
||||
import org.geysermc.connector.network.translators.item.ItemTranslator;
|
||||
import org.geysermc.connector.network.translators.sound.SoundHandlerRegistry;
|
||||
import org.geysermc.connector.network.translators.world.WorldManager;
|
||||
import org.geysermc.connector.thread.PingPassthroughThread;
|
||||
import org.geysermc.connector.utils.Toolbox;
|
||||
import org.geysermc.connector.network.translators.world.block.BlockTranslator;
|
||||
import org.geysermc.connector.network.translators.effect.EffectRegistry;
|
||||
import org.geysermc.connector.network.translators.world.block.entity.BlockEntityTranslator;
|
||||
import org.geysermc.connector.utils.DimensionUtils;
|
||||
import org.geysermc.connector.utils.DockerCheck;
|
||||
import org.geysermc.connector.utils.LocaleUtils;
|
||||
import org.geysermc.connector.network.translators.sound.SoundRegistry;
|
||||
|
||||
import java.net.InetSocketAddress;
|
||||
import java.text.DecimalFormat;
|
||||
|
@ -54,6 +66,8 @@ import java.util.concurrent.TimeUnit;
|
|||
@Getter
|
||||
public class GeyserConnector {
|
||||
|
||||
public static final ObjectMapper JSON_MAPPER = new ObjectMapper().disable(DeserializationFeature.FAIL_ON_IGNORED_PROPERTIES);
|
||||
|
||||
public static final BedrockPacketCodec BEDROCK_PACKET_CODEC = Bedrock_v390.V390_CODEC;
|
||||
|
||||
public static final String NAME = "Geyser";
|
||||
|
@ -69,7 +83,6 @@ public class GeyserConnector {
|
|||
private boolean shuttingDown = false;
|
||||
|
||||
private final ScheduledExecutorService generalThreadPool;
|
||||
private PingPassthroughThread passthroughThread;
|
||||
|
||||
private BedrockServer bedrockServer;
|
||||
private PlatformType platformType;
|
||||
|
@ -99,15 +112,29 @@ public class GeyserConnector {
|
|||
|
||||
logger.setDebug(config.isDebugMode());
|
||||
|
||||
Toolbox.init();
|
||||
Translators.start();
|
||||
PacketTranslatorRegistry.init();
|
||||
|
||||
/* Initialize translators and registries */
|
||||
BiomeTranslator.init();
|
||||
BlockTranslator.init();
|
||||
BlockEntityTranslator.init();
|
||||
EffectRegistry.init();
|
||||
EntityIdentifierRegistry.init();
|
||||
ItemRegistry.init();
|
||||
ItemTranslator.init();
|
||||
LocaleUtils.init();
|
||||
SoundRegistry.init();
|
||||
SoundHandlerRegistry.init();
|
||||
|
||||
if (platformType != PlatformType.STANDALONE) {
|
||||
DockerCheck.check(bootstrap);
|
||||
}
|
||||
|
||||
remoteServer = new RemoteServer(config.getRemote().getAddress(), config.getRemote().getPort());
|
||||
authType = AuthType.getByName(config.getRemote().getAuthType());
|
||||
|
||||
passthroughThread = new PingPassthroughThread(this);
|
||||
if (config.isPingPassthrough())
|
||||
generalThreadPool.scheduleAtFixedRate(passthroughThread, 1, 1, TimeUnit.SECONDS);
|
||||
if (config.isAboveBedrockNetherBuilding())
|
||||
DimensionUtils.changeBedrockNetherId(); // Apply End dimension ID workaround to Nether
|
||||
|
||||
bedrockServer = new BedrockServer(new InetSocketAddress(config.getBedrock().getAddress(), config.getBedrock().getPort()));
|
||||
bedrockServer.setHandler(new ConnectorServerEventHandler(this));
|
||||
|
|
|
@ -26,6 +26,7 @@
|
|||
|
||||
package org.geysermc.connector.bootstrap;
|
||||
|
||||
import org.geysermc.connector.ping.IGeyserPingPassthrough;
|
||||
import org.geysermc.connector.GeyserConfiguration;
|
||||
import org.geysermc.connector.GeyserLogger;
|
||||
import org.geysermc.connector.command.CommandManager;
|
||||
|
@ -67,6 +68,13 @@ public interface GeyserBootstrap {
|
|||
*/
|
||||
CommandManager getGeyserCommandManager();
|
||||
|
||||
/**
|
||||
* Returns the current PingPassthrough manager
|
||||
*
|
||||
* @return The current PingPassthrough manager
|
||||
*/
|
||||
IGeyserPingPassthrough getGeyserPingPassthrough();
|
||||
|
||||
/**
|
||||
* Returns the current WorldManager
|
||||
*
|
||||
|
|
|
@ -56,6 +56,16 @@ public class OffhandCommand extends GeyserCommand {
|
|||
ClientPlayerActionPacket releaseItemPacket = new ClientPlayerActionPacket(PlayerAction.SWAP_HANDS, new Position(0,0,0),
|
||||
BlockFace.DOWN);
|
||||
session.sendDownstreamPacket(releaseItemPacket);
|
||||
return;
|
||||
}
|
||||
// Needed for Bukkit - sender is not an instance of GeyserSession
|
||||
for (GeyserSession session : connector.getPlayers().values()) {
|
||||
if (sender.getName().equals(session.getPlayerEntity().getUsername())) {
|
||||
ClientPlayerActionPacket releaseItemPacket = new ClientPlayerActionPacket(PlayerAction.SWAP_HANDS, new Position(0,0,0),
|
||||
BlockFace.DOWN);
|
||||
session.sendDownstreamPacket(releaseItemPacket);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,50 @@
|
|||
/*
|
||||
* Copyright (c) 2019-2020 GeyserMC. http://geysermc.org
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*
|
||||
* @author GeyserMC
|
||||
* @link https://github.com/GeyserMC/Geyser
|
||||
*/
|
||||
|
||||
package org.geysermc.connector.entity;
|
||||
|
||||
import com.github.steveice10.mc.protocol.data.game.entity.metadata.EntityMetadata;
|
||||
import com.nukkitx.math.vector.Vector3f;
|
||||
import com.nukkitx.protocol.bedrock.data.EntityFlag;
|
||||
import org.geysermc.connector.entity.type.EntityType;
|
||||
import org.geysermc.connector.network.session.GeyserSession;
|
||||
|
||||
public class AbstractArrowEntity extends Entity {
|
||||
|
||||
public AbstractArrowEntity(long entityId, long geyserId, EntityType entityType, Vector3f position, Vector3f motion, Vector3f rotation) {
|
||||
super(entityId, geyserId, entityType, position, motion, rotation);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateBedrockMetadata(EntityMetadata entityMetadata, GeyserSession session) {
|
||||
if (entityMetadata.getId() == 7) {
|
||||
byte data = (byte) entityMetadata.getValue();
|
||||
|
||||
metadata.getFlags().setFlag(EntityFlag.CRITICAL, (data & 0x01) == 0x01);
|
||||
}
|
||||
|
||||
super.updateBedrockMetadata(entityMetadata, session);
|
||||
}
|
||||
}
|
|
@ -31,7 +31,7 @@ import com.nukkitx.math.vector.Vector3f;
|
|||
import com.nukkitx.protocol.bedrock.data.EntityData;
|
||||
import org.geysermc.connector.entity.type.EntityType;
|
||||
import org.geysermc.connector.network.session.GeyserSession;
|
||||
import org.geysermc.connector.utils.EffectUtils;
|
||||
import org.geysermc.connector.network.translators.effect.EffectRegistry;
|
||||
|
||||
public class AreaEffectCloudEntity extends Entity {
|
||||
|
||||
|
@ -52,7 +52,7 @@ public class AreaEffectCloudEntity extends Entity {
|
|||
metadata.put(EntityData.BOUNDING_BOX_WIDTH, 2.0f * (float) entityMetadata.getValue());
|
||||
} else if (entityMetadata.getId() == 10) {
|
||||
Particle particle = (Particle) entityMetadata.getValue();
|
||||
metadata.put(EntityData.AREA_EFFECT_CLOUD_PARTICLE_ID, EffectUtils.getParticleString(particle.getType()));
|
||||
metadata.put(EntityData.AREA_EFFECT_CLOUD_PARTICLE_ID, EffectRegistry.getParticleString(particle.getType()));
|
||||
} else if (entityMetadata.getId() == 8) {
|
||||
metadata.put(EntityData.POTION_COLOR, entityMetadata.getValue());
|
||||
}
|
||||
|
|
|
@ -0,0 +1,138 @@
|
|||
/*
|
||||
* Copyright (c) 2019-2020 GeyserMC. http://geysermc.org
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*
|
||||
* @author GeyserMC
|
||||
* @link https://github.com/GeyserMC/Geyser
|
||||
*/
|
||||
|
||||
package org.geysermc.connector.entity;
|
||||
|
||||
import com.github.steveice10.mc.protocol.data.game.entity.metadata.EntityMetadata;
|
||||
import com.nukkitx.math.vector.Vector3f;
|
||||
import com.nukkitx.protocol.bedrock.data.EntityData;
|
||||
import org.geysermc.connector.entity.type.EntityType;
|
||||
import org.geysermc.connector.network.session.GeyserSession;
|
||||
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
public class BoatEntity extends Entity {
|
||||
|
||||
private boolean isPaddlingLeft;
|
||||
private float paddleTimeLeft;
|
||||
private boolean isPaddlingRight;
|
||||
private float paddleTimeRight;
|
||||
|
||||
// Looks too fast and too choppy with 0.1f, which is how I believe the Microsoftian client handles it
|
||||
private final float ROWING_SPEED = 0.05f;
|
||||
|
||||
public BoatEntity(long entityId, long geyserId, EntityType entityType, Vector3f position, Vector3f motion, Vector3f rotation) {
|
||||
super(entityId, geyserId, entityType, position.add(0d, entityType.getOffset(), 0d), motion, rotation.add(0, 0, 90));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void moveAbsolute(GeyserSession session, Vector3f position, Vector3f rotation, boolean isOnGround, boolean teleported) {
|
||||
// Rotation is basically only called when entering/exiting a boat.
|
||||
// We don't include the rotation (y) as it causes the boat to appear sideways
|
||||
super.moveAbsolute(session, position.add(0d, this.entityType.getOffset(), 0d), Vector3f.from(0, 0, rotation.getZ() + 90), isOnGround, teleported);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void moveRelative(GeyserSession session, double relX, double relY, double relZ, Vector3f rotation, boolean isOnGround) {
|
||||
super.moveRelative(session, relX, relY, relZ, Vector3f.from(0, 0, rotation.getZ()), isOnGround);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateBedrockMetadata(EntityMetadata entityMetadata, GeyserSession session) {
|
||||
|
||||
// Time since last hit
|
||||
if (entityMetadata.getId() == 7) {
|
||||
metadata.put(EntityData.HURT_TIME, entityMetadata.getValue());
|
||||
}
|
||||
|
||||
// Rocking direction
|
||||
if (entityMetadata.getId() == 8) {
|
||||
metadata.put(EntityData.HURT_DIRECTION, entityMetadata.getValue());
|
||||
}
|
||||
|
||||
// 'Health' in Bedrock, damage taken in Java
|
||||
if (entityMetadata.getId() == 9) {
|
||||
// Not exactly health but it makes motion in Bedrock
|
||||
metadata.put(EntityData.HEALTH, 40 - ((int) (float) entityMetadata.getValue()));
|
||||
}
|
||||
|
||||
if (entityMetadata.getId() == 10) {
|
||||
metadata.put(EntityData.VARIANT, entityMetadata.getValue());
|
||||
} else if (entityMetadata.getId() == 11) {
|
||||
isPaddlingLeft = (boolean) entityMetadata.getValue();
|
||||
if (!isPaddlingLeft) {
|
||||
metadata.put(EntityData.PADDLE_TIME_LEFT, 0f);
|
||||
}
|
||||
else {
|
||||
// Java sends simply "true" and "false" (is_paddling_left), Bedrock keeps sending packets as you're rowing
|
||||
// This is an asynchronous method that emulates Bedrock rowing until "false" is sent.
|
||||
paddleTimeLeft = 0f;
|
||||
session.getConnector().getGeneralThreadPool().execute(() ->
|
||||
updateLeftPaddle(session, entityMetadata)
|
||||
);
|
||||
}
|
||||
}
|
||||
else if (entityMetadata.getId() == 12) {
|
||||
isPaddlingRight = (boolean) entityMetadata.getValue();
|
||||
if (!isPaddlingRight) {
|
||||
metadata.put(EntityData.PADDLE_TIME_RIGHT, 0f);
|
||||
} else {
|
||||
paddleTimeRight = 0f;
|
||||
session.getConnector().getGeneralThreadPool().execute(() ->
|
||||
updateRightPaddle(session, entityMetadata)
|
||||
);
|
||||
}
|
||||
} else if (entityMetadata.getId() == 13) {
|
||||
// Possibly - I don't think this does anything?
|
||||
metadata.put(EntityData.BOAT_BUBBLE_TIME, entityMetadata.getValue());
|
||||
}
|
||||
|
||||
super.updateBedrockMetadata(entityMetadata, session);
|
||||
}
|
||||
|
||||
public void updateLeftPaddle(GeyserSession session, EntityMetadata entityMetadata) {
|
||||
if (isPaddlingLeft) {
|
||||
paddleTimeLeft += ROWING_SPEED;
|
||||
metadata.put(EntityData.PADDLE_TIME_LEFT, paddleTimeLeft);
|
||||
super.updateBedrockMetadata(entityMetadata, session);
|
||||
session.getConnector().getGeneralThreadPool().schedule(() ->
|
||||
updateLeftPaddle(session, entityMetadata),
|
||||
100,
|
||||
TimeUnit.MILLISECONDS
|
||||
);
|
||||
}}
|
||||
|
||||
public void updateRightPaddle(GeyserSession session, EntityMetadata entityMetadata) {
|
||||
if (isPaddlingRight) {
|
||||
paddleTimeRight += ROWING_SPEED;
|
||||
metadata.put(EntityData.PADDLE_TIME_RIGHT, paddleTimeRight);
|
||||
super.updateBedrockMetadata(entityMetadata, session);
|
||||
session.getConnector().getGeneralThreadPool().schedule(() ->
|
||||
updateRightPaddle(session, entityMetadata),
|
||||
100,
|
||||
TimeUnit.MILLISECONDS
|
||||
);
|
||||
}}
|
||||
}
|
|
@ -0,0 +1,88 @@
|
|||
/*
|
||||
* Copyright (c) 2019-2020 GeyserMC. http://geysermc.org
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*
|
||||
* @author GeyserMC
|
||||
* @link https://github.com/GeyserMC/Geyser
|
||||
*/
|
||||
|
||||
package org.geysermc.connector.entity;
|
||||
|
||||
import com.github.steveice10.mc.protocol.data.game.entity.metadata.EntityMetadata;
|
||||
import com.nukkitx.math.vector.Vector3f;
|
||||
import com.nukkitx.protocol.bedrock.data.EntityData;
|
||||
import org.geysermc.connector.entity.type.EntityType;
|
||||
import org.geysermc.connector.network.session.GeyserSession;
|
||||
import org.geysermc.connector.network.translators.world.block.BlockTranslator;
|
||||
|
||||
/**
|
||||
* This class is used as a base for minecarts with a default block to display like furnaces and spawners
|
||||
*/
|
||||
public class DefaultBlockMinecartEntity extends MinecartEntity {
|
||||
|
||||
public int customBlock = 0;
|
||||
public int customBlockOffset = 0;
|
||||
public boolean showCustomBlock = false;
|
||||
|
||||
public DefaultBlockMinecartEntity(long entityId, long geyserId, EntityType entityType, Vector3f position, Vector3f motion, Vector3f rotation) {
|
||||
super(entityId, geyserId, entityType, position, motion, rotation);
|
||||
|
||||
updateDefaultBlockMetadata();
|
||||
metadata.put(EntityData.HAS_DISPLAY, (byte) 1);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateBedrockMetadata(EntityMetadata entityMetadata, GeyserSession session) {
|
||||
|
||||
// Custom block
|
||||
if (entityMetadata.getId() == 10) {
|
||||
customBlock = (int) entityMetadata.getValue();
|
||||
|
||||
if (showCustomBlock) {
|
||||
metadata.put(EntityData.DISPLAY_ITEM, BlockTranslator.getBedrockBlockId(customBlock));
|
||||
}
|
||||
}
|
||||
|
||||
// Custom block offset
|
||||
if (entityMetadata.getId() == 11) {
|
||||
customBlockOffset = (int) entityMetadata.getValue();
|
||||
|
||||
if (showCustomBlock) {
|
||||
metadata.put(EntityData.DISPLAY_OFFSET, customBlockOffset);
|
||||
}
|
||||
}
|
||||
|
||||
// If the custom block should be enabled
|
||||
if (entityMetadata.getId() == 12) {
|
||||
if ((boolean) entityMetadata.getValue()) {
|
||||
showCustomBlock = true;
|
||||
metadata.put(EntityData.DISPLAY_ITEM, BlockTranslator.getBedrockBlockId(customBlock));
|
||||
metadata.put(EntityData.DISPLAY_OFFSET, customBlockOffset);
|
||||
} else {
|
||||
showCustomBlock = false;
|
||||
updateDefaultBlockMetadata();
|
||||
}
|
||||
}
|
||||
|
||||
super.updateBedrockMetadata(entityMetadata, session);
|
||||
}
|
||||
|
||||
public void updateDefaultBlockMetadata() { }
|
||||
}
|
|
@ -27,21 +27,24 @@ 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.MetadataType;
|
||||
import com.github.steveice10.mc.protocol.data.game.entity.metadata.Pose;
|
||||
import com.github.steveice10.mc.protocol.data.game.entity.metadata.Position;
|
||||
import com.github.steveice10.mc.protocol.data.game.entity.player.Hand;
|
||||
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.BlockState;
|
||||
import com.github.steveice10.mc.protocol.data.message.TextMessage;
|
||||
import com.github.steveice10.mc.protocol.data.message.TranslationMessage;
|
||||
import com.github.steveice10.mc.protocol.packet.ingame.client.player.ClientPlayerActionPacket;
|
||||
import com.github.steveice10.mc.protocol.packet.ingame.client.player.ClientPlayerUseItemPacket;
|
||||
import com.nukkitx.math.vector.Vector3f;
|
||||
import com.nukkitx.math.vector.Vector3i;
|
||||
import com.nukkitx.protocol.bedrock.data.EntityData;
|
||||
import com.nukkitx.protocol.bedrock.data.EntityDataMap;
|
||||
import com.nukkitx.protocol.bedrock.data.EntityFlag;
|
||||
import com.nukkitx.protocol.bedrock.data.EntityFlags;
|
||||
import com.nukkitx.protocol.bedrock.packet.*;
|
||||
import it.unimi.dsi.fastutil.longs.LongOpenHashSet;
|
||||
import it.unimi.dsi.fastutil.longs.LongSet;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
import org.geysermc.connector.entity.attribute.Attribute;
|
||||
|
@ -49,8 +52,9 @@ import org.geysermc.connector.entity.attribute.AttributeType;
|
|||
import org.geysermc.connector.entity.living.ArmorStandEntity;
|
||||
import org.geysermc.connector.entity.type.EntityType;
|
||||
import org.geysermc.connector.network.session.GeyserSession;
|
||||
import org.geysermc.connector.network.translators.item.ItemTranslator;
|
||||
import org.geysermc.connector.network.translators.item.ItemRegistry;
|
||||
import org.geysermc.connector.utils.AttributeUtils;
|
||||
import org.geysermc.connector.utils.ChunkUtils;
|
||||
import org.geysermc.connector.utils.MessageUtils;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
@ -80,7 +84,7 @@ public class Entity {
|
|||
|
||||
protected boolean valid;
|
||||
|
||||
protected LongSet passengers = new LongOpenHashSet();
|
||||
protected LongOpenHashSet passengers = new LongOpenHashSet();
|
||||
protected Map<AttributeType, Attribute> attributes = new HashMap<>();
|
||||
protected EntityDataMap metadata = new EntityDataMap();
|
||||
|
||||
|
@ -98,7 +102,7 @@ public class Entity {
|
|||
|
||||
metadata.put(EntityData.SCALE, 1f);
|
||||
metadata.put(EntityData.COLOR, 0);
|
||||
metadata.put(EntityData.MAX_AIR, (short) 400);
|
||||
metadata.put(EntityData.MAX_AIR, (short) 300);
|
||||
metadata.put(EntityData.AIR, (short) 0);
|
||||
metadata.put(EntityData.LEAD_HOLDER_EID, -1L);
|
||||
metadata.put(EntityData.BOUNDING_BOX_HEIGHT, entityType.getHeight());
|
||||
|
@ -210,9 +214,8 @@ public class Entity {
|
|||
metadata.getFlags().setFlag(EntityFlag.GLIDING, (xd & 0x80) == 0x80);
|
||||
|
||||
if ((xd & 0x20) == 0x20) {
|
||||
if (this.is(ArmorStandEntity.class)) {
|
||||
metadata.put(EntityData.SCALE, 0.0f);
|
||||
} else {
|
||||
// Armour stands are handled in their own class
|
||||
if (!this.is(ArmorStandEntity.class)) {
|
||||
metadata.getFlags().setFlag(EntityFlag.INVISIBLE, true);
|
||||
}
|
||||
} else {
|
||||
|
@ -221,11 +224,11 @@ public class Entity {
|
|||
|
||||
// Shield code
|
||||
if (session.getPlayerEntity().getEntityId() == entityId && metadata.getFlags().getFlag(EntityFlag.SNEAKING)) {
|
||||
if ((session.getInventory().getItemInHand() != null && session.getInventory().getItemInHand().getId() == ItemTranslator.SHIELD) ||
|
||||
(session.getInventoryCache().getPlayerInventory().getItem(45) != null && session.getInventoryCache().getPlayerInventory().getItem(45).getId() == ItemTranslator.SHIELD)) {
|
||||
if ((session.getInventory().getItemInHand() != null && session.getInventory().getItemInHand().getId() == ItemRegistry.SHIELD) ||
|
||||
(session.getInventoryCache().getPlayerInventory().getItem(45) != null && session.getInventoryCache().getPlayerInventory().getItem(45).getId() == ItemRegistry.SHIELD)) {
|
||||
ClientPlayerUseItemPacket useItemPacket;
|
||||
metadata.getFlags().setFlag(EntityFlag.BLOCKING, true);
|
||||
if (session.getInventory().getItemInHand() != null && session.getInventory().getItemInHand().getId() == ItemTranslator.SHIELD) {
|
||||
if (session.getInventory().getItemInHand() != null && session.getInventory().getItemInHand().getId() == ItemRegistry.SHIELD) {
|
||||
useItemPacket = new ClientPlayerUseItemPacket(Hand.MAIN_HAND);
|
||||
}
|
||||
// Else we just assume it's the offhand, to simplify logic and to assure the packet gets sent
|
||||
|
@ -242,10 +245,23 @@ public class Entity {
|
|||
}
|
||||
}
|
||||
break;
|
||||
case 1: // Air/bubbles
|
||||
if ((int) entityMetadata.getValue() == 300) {
|
||||
metadata.put(EntityData.AIR, (short) 0); // Otherwise the bubble counter remains in the UI
|
||||
} else {
|
||||
metadata.put(EntityData.AIR, (short) (int) entityMetadata.getValue());
|
||||
}
|
||||
break;
|
||||
case 2: // custom name
|
||||
if (entityMetadata.getValue() instanceof TextMessage) {
|
||||
TextMessage name = (TextMessage) entityMetadata.getValue();
|
||||
if (name != null)
|
||||
metadata.put(EntityData.NAMETAG, MessageUtils.getBedrockMessage(name));
|
||||
} else if (entityMetadata.getValue() instanceof TranslationMessage) {
|
||||
TranslationMessage message = (TranslationMessage) entityMetadata.getValue();
|
||||
if (message != null)
|
||||
metadata.put(EntityData.NAMETAG, MessageUtils.getTranslatedBedrockMessage(message, session.getClientData().getLanguageCode(), true));
|
||||
}
|
||||
break;
|
||||
case 3: // is custom name visible
|
||||
if (!this.is(PlayerEntity.class))
|
||||
|
@ -257,6 +273,32 @@ public class Entity {
|
|||
case 5: // no gravity
|
||||
metadata.getFlags().setFlag(EntityFlag.HAS_GRAVITY, !(boolean) entityMetadata.getValue());
|
||||
break;
|
||||
case 6: // Pose change
|
||||
if (entityMetadata.getValue().equals(Pose.SLEEPING)) {
|
||||
metadata.getFlags().setFlag(EntityFlag.SLEEPING, true);
|
||||
// Has to be a byte or it does not work
|
||||
metadata.put(EntityData.CAN_START_SLEEP, (byte) 2);
|
||||
if (entityId == session.getPlayerEntity().getEntityId()) {
|
||||
Vector3i lastInteractionPos = session.getLastInteractionPosition();
|
||||
metadata.put(EntityData.BED_RESPAWN_POS, lastInteractionPos);
|
||||
if (session.getConnector().getConfig().isCacheChunks()) {
|
||||
BlockState bed = session.getConnector().getWorldManager().getBlockAt(session, lastInteractionPos.getX(),
|
||||
lastInteractionPos.getY(), lastInteractionPos.getZ());
|
||||
// Bed has to be updated, or else player is floating in the air
|
||||
ChunkUtils.updateBlock(session, bed, lastInteractionPos);
|
||||
}
|
||||
} else {
|
||||
metadata.put(EntityData.BED_RESPAWN_POS, Vector3i.from(position.getFloorX(), position.getFloorY() - 2, position.getFloorZ()));
|
||||
}
|
||||
metadata.put(EntityData.BOUNDING_BOX_WIDTH, 0.2f);
|
||||
metadata.put(EntityData.BOUNDING_BOX_HEIGHT, 0.2f);
|
||||
} else if (metadata.getFlags().getFlag(EntityFlag.SLEEPING)) {
|
||||
metadata.getFlags().setFlag(EntityFlag.SLEEPING, false);
|
||||
metadata.put(EntityData.BOUNDING_BOX_WIDTH, getEntityType().getWidth());
|
||||
metadata.put(EntityData.BOUNDING_BOX_HEIGHT, getEntityType().getHeight());
|
||||
metadata.put(EntityData.CAN_START_SLEEP, (byte) 0);
|
||||
}
|
||||
break;
|
||||
case 7: // blocking
|
||||
if (entityMetadata.getType() == MetadataType.BYTE) {
|
||||
byte xd = (byte) entityMetadata.getValue();
|
||||
|
|
|
@ -0,0 +1,139 @@
|
|||
/*
|
||||
* Copyright (c) 2019-2020 GeyserMC. http://geysermc.org
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*
|
||||
* @author GeyserMC
|
||||
* @link https://github.com/GeyserMC/Geyser
|
||||
*/
|
||||
|
||||
package org.geysermc.connector.entity;
|
||||
|
||||
import com.github.steveice10.mc.protocol.data.game.entity.metadata.EntityMetadata;
|
||||
import com.github.steveice10.mc.protocol.data.game.entity.metadata.ItemStack;
|
||||
import com.github.steveice10.opennbt.tag.builtin.CompoundTag;
|
||||
import com.github.steveice10.opennbt.tag.builtin.ListTag;
|
||||
import com.github.steveice10.opennbt.tag.builtin.Tag;
|
||||
import com.nukkitx.math.vector.Vector3f;
|
||||
import com.nukkitx.nbt.CompoundTagBuilder;
|
||||
import com.nukkitx.protocol.bedrock.data.EntityData;
|
||||
import com.nukkitx.protocol.bedrock.packet.SetEntityMotionPacket;
|
||||
import org.geysermc.connector.entity.type.EntityType;
|
||||
import org.geysermc.connector.network.session.GeyserSession;
|
||||
import org.geysermc.connector.utils.FireworkColor;
|
||||
import org.geysermc.connector.utils.MathUtils;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.OptionalInt;
|
||||
|
||||
public class FireworkEntity extends Entity {
|
||||
|
||||
public FireworkEntity(long entityId, long geyserId, EntityType entityType, Vector3f position, Vector3f motion, Vector3f rotation) {
|
||||
super(entityId, geyserId, entityType, position, motion, rotation);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void updateBedrockMetadata(EntityMetadata entityMetadata, GeyserSession session) {
|
||||
if (entityMetadata.getId() == 7) {
|
||||
ItemStack item = (ItemStack) entityMetadata.getValue();
|
||||
CompoundTag tag = item.getNbt();
|
||||
|
||||
if (tag == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
CompoundTag fireworks = tag.get("Fireworks");
|
||||
|
||||
CompoundTagBuilder fireworksBuilder = CompoundTagBuilder.builder();
|
||||
if (fireworks.get("Flight") != null) {
|
||||
fireworksBuilder.byteTag("Flight", MathUtils.convertByte(fireworks.get("Flight").getValue()));
|
||||
}
|
||||
|
||||
List<com.nukkitx.nbt.tag.CompoundTag> explosions = new ArrayList<>();
|
||||
if (fireworks.get("Explosions") != null) {
|
||||
for (Tag effect : ((ListTag) fireworks.get("Explosions")).getValue()) {
|
||||
CompoundTag effectData = (CompoundTag) effect;
|
||||
CompoundTagBuilder effectBuilder = CompoundTagBuilder.builder();
|
||||
|
||||
if (effectData.get("Type") != null) {
|
||||
effectBuilder.byteTag("FireworkType", MathUtils.convertByte(effectData.get("Type").getValue()));
|
||||
}
|
||||
|
||||
if (effectData.get("Colors") != null) {
|
||||
int[] oldColors = (int[]) effectData.get("Colors").getValue();
|
||||
byte[] colors = new byte[oldColors.length];
|
||||
|
||||
int i = 0;
|
||||
for (int color : oldColors) {
|
||||
colors[i++] = FireworkColor.fromJavaID(color).getBedrockID();
|
||||
}
|
||||
|
||||
effectBuilder.byteArrayTag("FireworkColor", colors);
|
||||
}
|
||||
|
||||
if (effectData.get("FadeColors") != null) {
|
||||
int[] oldColors = (int[]) effectData.get("FadeColors").getValue();
|
||||
byte[] colors = new byte[oldColors.length];
|
||||
|
||||
int i = 0;
|
||||
for (int color : oldColors) {
|
||||
colors[i++] = FireworkColor.fromJavaID(color).getBedrockID();
|
||||
}
|
||||
|
||||
effectBuilder.byteArrayTag("FireworkFade", colors);
|
||||
}
|
||||
|
||||
if (effectData.get("Trail") != null) {
|
||||
effectBuilder.byteTag("FireworkTrail", MathUtils.convertByte(effectData.get("Trail").getValue()));
|
||||
}
|
||||
|
||||
if (effectData.get("Flicker") != null) {
|
||||
effectBuilder.byteTag("FireworkFlicker", MathUtils.convertByte(effectData.get("Flicker").getValue()));
|
||||
}
|
||||
|
||||
explosions.add(effectBuilder.buildRootTag());
|
||||
}
|
||||
}
|
||||
|
||||
fireworksBuilder.tag(new com.nukkitx.nbt.tag.ListTag<>("Explosions", com.nukkitx.nbt.tag.CompoundTag.class, explosions));
|
||||
|
||||
metadata.put(EntityData.DISPLAY_ITEM, CompoundTagBuilder.builder().tag(fireworksBuilder.build("Fireworks")).buildRootTag());
|
||||
} else if (entityMetadata.getId() == 8 && !entityMetadata.getValue().equals(OptionalInt.empty()) && ((OptionalInt) entityMetadata.getValue()).getAsInt() == session.getPlayerEntity().getEntityId()) {
|
||||
//Checks if the firework has an entity ID (used when a player is gliding) and checks to make sure the player that is gliding is the one getting sent the packet or else every player near the gliding player will boost too.
|
||||
PlayerEntity entity = session.getPlayerEntity();
|
||||
float yaw = entity.getRotation().getX();
|
||||
float pitch = entity.getRotation().getY();
|
||||
//Uses math from NukkitX
|
||||
entity.setMotion(Vector3f.from(
|
||||
-Math.sin(Math.toRadians(yaw)) * Math.cos(Math.toRadians(pitch)) * 2,
|
||||
-Math.sin(Math.toRadians(pitch)) * 2,
|
||||
Math.cos(Math.toRadians(yaw)) * Math.cos(Math.toRadians(pitch)) * 2));
|
||||
//Need to update the EntityMotionPacket or else the player won't boost
|
||||
SetEntityMotionPacket entityMotionPacket = new SetEntityMotionPacket();
|
||||
entityMotionPacket.setRuntimeEntityId(entity.getGeyserId());
|
||||
entityMotionPacket.setMotion(entity.getMotion());
|
||||
|
||||
session.sendUpstreamPacket(entityMotionPacket);
|
||||
}
|
||||
|
||||
super.updateBedrockMetadata(entityMetadata, session);
|
||||
}
|
||||
}
|
|
@ -26,7 +26,7 @@
|
|||
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.type.object.ProjectileData;
|
||||
import com.github.steveice10.mc.protocol.data.game.entity.object.ProjectileData;
|
||||
import com.nukkitx.math.vector.Vector3f;
|
||||
import com.nukkitx.protocol.bedrock.data.EntityData;
|
||||
import org.geysermc.connector.GeyserConnector;
|
||||
|
@ -37,10 +37,14 @@ public class FishingHookEntity extends Entity {
|
|||
public FishingHookEntity(long entityId, long geyserId, EntityType entityType, Vector3f position, Vector3f motion, Vector3f rotation, ProjectileData data) {
|
||||
super(entityId, geyserId, entityType, position, motion, rotation);
|
||||
|
||||
// TODO: Find a better way to do this
|
||||
for (GeyserSession session : GeyserConnector.getInstance().getPlayers().values()) {
|
||||
if (session.getPlayerEntity().getEntityId() == data.getOwnerId()) {
|
||||
this.metadata.put(EntityData.OWNER_EID, session.getPlayerEntity().getGeyserId());
|
||||
Entity entity = session.getEntityCache().getEntityByJavaId(data.getOwnerId());
|
||||
if (entity == null && session.getPlayerEntity().getEntityId() == data.getOwnerId()) {
|
||||
entity = session.getPlayerEntity();
|
||||
}
|
||||
|
||||
if (entity != null) {
|
||||
this.metadata.put(EntityData.OWNER_EID, entity.getGeyserId());
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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 com.nukkitx.protocol.bedrock.data.EntityData;
|
||||
import org.geysermc.connector.entity.type.EntityType;
|
||||
import org.geysermc.connector.network.session.GeyserSession;
|
||||
import org.geysermc.connector.network.translators.world.block.BlockTranslator;
|
||||
|
||||
public class FurnaceMinecartEntity extends DefaultBlockMinecartEntity {
|
||||
|
||||
private boolean hasFuel = false;
|
||||
|
||||
public FurnaceMinecartEntity(long entityId, long geyserId, EntityType entityType, Vector3f position, Vector3f motion, Vector3f rotation) {
|
||||
super(entityId, geyserId, entityType, position, motion, rotation);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateBedrockMetadata(EntityMetadata entityMetadata, GeyserSession session) {
|
||||
if (entityMetadata.getId() == 13 && !showCustomBlock) {
|
||||
hasFuel = (boolean) entityMetadata.getValue();
|
||||
updateDefaultBlockMetadata();
|
||||
}
|
||||
|
||||
super.updateBedrockMetadata(entityMetadata, session);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateDefaultBlockMetadata() {
|
||||
metadata.put(EntityData.DISPLAY_ITEM, BlockTranslator.getBedrockBlockId(hasFuel ? BlockTranslator.JAVA_RUNTIME_FURNACE_LIT_ID : BlockTranslator.JAVA_RUNTIME_FURNACE_ID));
|
||||
metadata.put(EntityData.DISPLAY_OFFSET, 6);
|
||||
}
|
||||
}
|
|
@ -31,7 +31,7 @@ import com.nukkitx.math.vector.Vector3f;
|
|||
import com.nukkitx.protocol.bedrock.packet.AddItemEntityPacket;
|
||||
import org.geysermc.connector.entity.type.EntityType;
|
||||
import org.geysermc.connector.network.session.GeyserSession;
|
||||
import org.geysermc.connector.network.translators.Translators;
|
||||
import org.geysermc.connector.network.translators.item.ItemTranslator;
|
||||
|
||||
public class ItemEntity extends Entity {
|
||||
|
||||
|
@ -49,7 +49,7 @@ public class ItemEntity extends Entity {
|
|||
itemPacket.setUniqueEntityId(geyserId);
|
||||
itemPacket.setFromFishing(false);
|
||||
itemPacket.getMetadata().putAll(metadata);
|
||||
itemPacket.setItemInHand(Translators.getItemTranslator().translateToBedrock(session, (ItemStack) entityMetadata.getValue()));
|
||||
itemPacket.setItemInHand(ItemTranslator.translateToBedrock(session, (ItemStack) entityMetadata.getValue()));
|
||||
session.sendUpstreamPacket(itemPacket);
|
||||
}
|
||||
|
||||
|
|
|
@ -27,7 +27,7 @@ package org.geysermc.connector.entity;
|
|||
|
||||
import com.github.steveice10.mc.protocol.data.game.entity.metadata.EntityMetadata;
|
||||
import com.github.steveice10.mc.protocol.data.game.entity.metadata.ItemStack;
|
||||
import com.github.steveice10.mc.protocol.data.game.entity.type.object.HangingDirection;
|
||||
import com.github.steveice10.mc.protocol.data.game.entity.object.HangingDirection;
|
||||
import com.nukkitx.math.vector.Vector3f;
|
||||
import com.nukkitx.math.vector.Vector3i;
|
||||
import com.nukkitx.nbt.CompoundTagBuilder;
|
||||
|
@ -38,10 +38,10 @@ import com.nukkitx.protocol.bedrock.packet.StartGamePacket;
|
|||
import com.nukkitx.protocol.bedrock.packet.UpdateBlockPacket;
|
||||
import org.geysermc.connector.entity.type.EntityType;
|
||||
import org.geysermc.connector.network.session.GeyserSession;
|
||||
import org.geysermc.connector.network.translators.Translators;
|
||||
import org.geysermc.connector.network.translators.item.ItemEntry;
|
||||
import org.geysermc.connector.network.translators.item.ItemRegistry;
|
||||
import org.geysermc.connector.network.translators.item.ItemTranslator;
|
||||
import org.geysermc.connector.network.translators.world.block.BlockTranslator;
|
||||
import org.geysermc.connector.utils.Toolbox;
|
||||
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
|
@ -87,20 +87,23 @@ public class ItemFrameEntity extends Entity {
|
|||
@Override
|
||||
public void spawnEntity(GeyserSession session) {
|
||||
session.getItemFrameCache().put(bedrockPosition, entityId);
|
||||
// Delay is required, or else loading in frames on chunk load is sketchy at best
|
||||
session.getConnector().getGeneralThreadPool().schedule(() -> {
|
||||
updateBlock(session);
|
||||
valid = true;
|
||||
session.getConnector().getLogger().debug("Spawned item frame at location " + bedrockPosition + " with java id " + entityId);
|
||||
}, 500, TimeUnit.MILLISECONDS);
|
||||
valid = true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateBedrockMetadata(EntityMetadata entityMetadata, GeyserSession session) {
|
||||
if (entityMetadata.getId() == 7 && entityMetadata.getValue() != null) {
|
||||
ItemData itemData = Translators.getItemTranslator().translateToBedrock(session, (ItemStack) entityMetadata.getValue());
|
||||
ItemEntry itemEntry = Translators.getItemTranslator().getItem((ItemStack) entityMetadata.getValue());
|
||||
ItemData itemData = ItemTranslator.translateToBedrock(session, (ItemStack) entityMetadata.getValue());
|
||||
ItemEntry itemEntry = ItemRegistry.getItem((ItemStack) entityMetadata.getValue());
|
||||
CompoundTagBuilder builder = CompoundTag.builder();
|
||||
|
||||
String blockName = "";
|
||||
for (StartGamePacket.ItemEntry startGamePacketItemEntry: Toolbox.ITEMS) {
|
||||
for (StartGamePacket.ItemEntry startGamePacketItemEntry : ItemRegistry.ITEMS) {
|
||||
if (startGamePacketItemEntry.getId() == (short) itemEntry.getBedrockId()) {
|
||||
blockName = startGamePacketItemEntry.getIdentifier();
|
||||
break;
|
||||
|
@ -170,8 +173,6 @@ public class ItemFrameEntity extends Entity {
|
|||
* @param session GeyserSession.
|
||||
*/
|
||||
public void updateBlock(GeyserSession session) {
|
||||
// Delay is required, or else loading in frames on chunk load is sketchy at best
|
||||
session.getConnector().getGeneralThreadPool().schedule(() -> {
|
||||
UpdateBlockPacket updateBlockPacket = new UpdateBlockPacket();
|
||||
updateBlockPacket.setDataLayer(0);
|
||||
updateBlockPacket.setBlockPosition(bedrockPosition);
|
||||
|
@ -190,7 +191,6 @@ public class ItemFrameEntity extends Entity {
|
|||
}
|
||||
|
||||
session.sendUpstreamPacket(blockEntityDataPacket);
|
||||
}, 500, TimeUnit.MILLISECONDS);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -0,0 +1,39 @@
|
|||
/*
|
||||
* Copyright (c) 2019-2020 GeyserMC. http://geysermc.org
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*
|
||||
* @author GeyserMC
|
||||
* @link https://github.com/GeyserMC/Geyser
|
||||
*
|
||||
*/
|
||||
|
||||
package org.geysermc.connector.entity;
|
||||
|
||||
import com.nukkitx.math.vector.Vector3f;
|
||||
import org.geysermc.connector.entity.type.EntityType;
|
||||
|
||||
public class LeashKnotEntity extends Entity {
|
||||
|
||||
public LeashKnotEntity(long entityId, long geyserId, EntityType entityType, Vector3f position, Vector3f motion, Vector3f rotation) {
|
||||
// Position is incorrect by default
|
||||
super(entityId, geyserId, entityType, position.add(0.5f, 0.25f, 0.5f), motion, rotation);
|
||||
}
|
||||
|
||||
}
|
|
@ -25,12 +25,59 @@
|
|||
|
||||
package org.geysermc.connector.entity;
|
||||
|
||||
import com.github.steveice10.mc.protocol.data.game.entity.metadata.EntityMetadata;
|
||||
import com.nukkitx.math.vector.Vector3f;
|
||||
import com.nukkitx.protocol.bedrock.data.EntityData;
|
||||
import org.geysermc.connector.entity.type.EntityType;
|
||||
import org.geysermc.connector.network.session.GeyserSession;
|
||||
import org.geysermc.connector.network.translators.world.block.BlockTranslator;
|
||||
|
||||
public class MinecartEntity extends Entity {
|
||||
|
||||
public MinecartEntity(long entityId, long geyserId, EntityType entityType, Vector3f position, Vector3f motion, Vector3f rotation) {
|
||||
super(entityId, geyserId, entityType, position, motion, rotation);
|
||||
super(entityId, geyserId, entityType, position.add(0d, entityType.getOffset(), 0d), motion, rotation);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateBedrockMetadata(EntityMetadata entityMetadata, GeyserSession session) {
|
||||
|
||||
if (entityMetadata.getId() == 7) {
|
||||
metadata.put(EntityData.HEALTH, entityMetadata.getValue());
|
||||
}
|
||||
|
||||
// Direction in which the minecart is shaking
|
||||
if (entityMetadata.getId() == 8) {
|
||||
metadata.put(EntityData.HURT_DIRECTION, entityMetadata.getValue());
|
||||
}
|
||||
|
||||
// Power in Java, time in Bedrock
|
||||
if (entityMetadata.getId() == 9) {
|
||||
metadata.put(EntityData.HURT_TIME, Math.min((int) (float) entityMetadata.getValue(), 15));
|
||||
}
|
||||
|
||||
if (!(this instanceof DefaultBlockMinecartEntity)) { // Handled in the DefaultBlockMinecartEntity class
|
||||
// Custom block
|
||||
if (entityMetadata.getId() == 10) {
|
||||
metadata.put(EntityData.DISPLAY_ITEM, BlockTranslator.getBedrockBlockId((int) entityMetadata.getValue()));
|
||||
}
|
||||
|
||||
// Custom block offset
|
||||
if (entityMetadata.getId() == 11) {
|
||||
metadata.put(EntityData.DISPLAY_OFFSET, entityMetadata.getValue());
|
||||
}
|
||||
|
||||
// If the custom block should be enabled
|
||||
if (entityMetadata.getId() == 12) {
|
||||
// Needs a byte based off of Java's boolean
|
||||
metadata.put(EntityData.HAS_DISPLAY, (byte) ((boolean) entityMetadata.getValue() ? 1 : 0));
|
||||
}
|
||||
}
|
||||
|
||||
super.updateBedrockMetadata(entityMetadata, session);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void moveAbsolute(GeyserSession session, Vector3f position, Vector3f rotation, boolean isOnGround, boolean teleported) {
|
||||
super.moveAbsolute(session, position.add(0d, this.entityType.getOffset(), 0d), rotation, isOnGround, teleported);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -67,7 +67,7 @@ public class PaintingEntity extends Entity {
|
|||
Vector3f position = super.position;
|
||||
position = position.add(0.5, 0.5, 0.5);
|
||||
double widthOffset = paintingName.getWidth() > 1 ? 0.5 : 0;
|
||||
double heightOffset = paintingName.getHeight() > 1 ? 0.5 : 0;
|
||||
double heightOffset = paintingName.getHeight() > 1 && paintingName.getHeight() != 3 ? 0.5 : 0;
|
||||
|
||||
switch (direction) {
|
||||
case 0: return position.add(widthOffset, heightOffset, OFFSET);
|
||||
|
|
|
@ -26,14 +26,12 @@
|
|||
package org.geysermc.connector.entity;
|
||||
|
||||
import com.github.steveice10.mc.auth.data.GameProfile;
|
||||
import com.github.steveice10.mc.protocol.data.game.entity.Effect;
|
||||
import com.github.steveice10.mc.protocol.data.game.entity.metadata.EntityMetadata;
|
||||
import com.github.steveice10.mc.protocol.data.message.TextMessage;
|
||||
import com.github.steveice10.opennbt.tag.builtin.CompoundTag;
|
||||
import com.nukkitx.math.vector.Vector3f;
|
||||
import com.nukkitx.protocol.bedrock.data.CommandPermission;
|
||||
import com.nukkitx.protocol.bedrock.data.EntityData;
|
||||
import com.nukkitx.protocol.bedrock.data.EntityLink;
|
||||
import com.nukkitx.protocol.bedrock.data.PlayerPermission;
|
||||
import com.nukkitx.protocol.bedrock.data.*;
|
||||
import com.nukkitx.protocol.bedrock.packet.*;
|
||||
|
||||
import lombok.Getter;
|
||||
|
@ -47,6 +45,8 @@ import org.geysermc.connector.utils.MessageUtils;
|
|||
import org.geysermc.connector.network.session.cache.EntityEffectCache;
|
||||
import org.geysermc.connector.utils.SkinUtils;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.UUID;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
|
@ -57,6 +57,7 @@ public class PlayerEntity extends LivingEntity {
|
|||
private String username;
|
||||
private long lastSkinUpdate = -1;
|
||||
private boolean playerList = true;
|
||||
private boolean onGround;
|
||||
private final EntityEffectCache effectCache;
|
||||
|
||||
private Entity leftParrot;
|
||||
|
@ -97,6 +98,11 @@ public class PlayerEntity extends LivingEntity {
|
|||
addPlayerPacket.setPlatformChatId("");
|
||||
addPlayerPacket.getMetadata().putAll(metadata);
|
||||
|
||||
long linkedEntityId = session.getEntityCache().getCachedPlayerEntityLink(entityId);
|
||||
if (linkedEntityId != -1) {
|
||||
addPlayerPacket.getEntityLinks().add(new EntityLink(session.getEntityCache().getEntityByJavaId(linkedEntityId).getGeyserId(), geyserId, EntityLink.Type.RIDER, false));
|
||||
}
|
||||
|
||||
valid = true;
|
||||
session.sendUpstreamPacket(addPlayerPacket);
|
||||
|
||||
|
@ -138,6 +144,8 @@ public class PlayerEntity extends LivingEntity {
|
|||
setPosition(position);
|
||||
setRotation(rotation);
|
||||
|
||||
this.onGround = isOnGround;
|
||||
|
||||
MovePlayerPacket movePlayerPacket = new MovePlayerPacket();
|
||||
movePlayerPacket.setRuntimeEntityId(geyserId);
|
||||
movePlayerPacket.setPosition(this.position);
|
||||
|
@ -163,6 +171,8 @@ public class PlayerEntity extends LivingEntity {
|
|||
setRotation(rotation);
|
||||
this.position = Vector3f.from(position.getX() + relX, position.getY() + relY, position.getZ() + relZ);
|
||||
|
||||
this.onGround = isOnGround;
|
||||
|
||||
MovePlayerPacket movePlayerPacket = new MovePlayerPacket();
|
||||
movePlayerPacket.setRuntimeEntityId(geyserId);
|
||||
movePlayerPacket.setPosition(position);
|
||||
|
@ -205,6 +215,17 @@ public class PlayerEntity extends LivingEntity {
|
|||
}
|
||||
}
|
||||
|
||||
// Extra hearts - is not metadata but an attribute on Bedrock
|
||||
if (entityMetadata.getId() == 14) {
|
||||
UpdateAttributesPacket attributesPacket = new UpdateAttributesPacket();
|
||||
attributesPacket.setRuntimeEntityId(geyserId);
|
||||
List<Attribute> attributes = new ArrayList<>();
|
||||
// Setting to a higher maximum since plugins/datapacks can probably extend the Bedrock soft limit
|
||||
attributes.add(new Attribute("minecraft:absorption", 0.0f, 1024f, (float) entityMetadata.getValue(), 0.0f));
|
||||
attributesPacket.setAttributes(attributes);
|
||||
session.sendUpstreamPacket(attributesPacket);
|
||||
}
|
||||
|
||||
// Parrot occupying shoulder
|
||||
if (entityMetadata.getId() == 18 || entityMetadata.getId() == 19) {
|
||||
CompoundTag tag = (CompoundTag) entityMetadata.getValue();
|
||||
|
|
|
@ -0,0 +1,44 @@
|
|||
/*
|
||||
* Copyright (c) 2019-2020 GeyserMC. http://geysermc.org
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*
|
||||
* @author GeyserMC
|
||||
* @link https://github.com/GeyserMC/Geyser
|
||||
*/
|
||||
|
||||
package org.geysermc.connector.entity;
|
||||
|
||||
import com.nukkitx.math.vector.Vector3f;
|
||||
import com.nukkitx.protocol.bedrock.data.EntityData;
|
||||
import org.geysermc.connector.entity.type.EntityType;
|
||||
import org.geysermc.connector.network.translators.world.block.BlockTranslator;
|
||||
|
||||
public class SpawnerMinecartEntity extends DefaultBlockMinecartEntity {
|
||||
|
||||
public SpawnerMinecartEntity(long entityId, long geyserId, EntityType entityType, Vector3f position, Vector3f motion, Vector3f rotation) {
|
||||
super(entityId, geyserId, entityType, position, motion, rotation);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateDefaultBlockMetadata() {
|
||||
metadata.put(EntityData.DISPLAY_ITEM, BlockTranslator.getBedrockBlockId(BlockTranslator.JAVA_RUNTIME_SPAWNER_ID));
|
||||
metadata.put(EntityData.DISPLAY_OFFSET, 6);
|
||||
}
|
||||
}
|
|
@ -28,9 +28,9 @@ package org.geysermc.connector.entity;
|
|||
import com.nukkitx.math.vector.Vector3f;
|
||||
import org.geysermc.connector.entity.type.EntityType;
|
||||
|
||||
public class ArrowEntity extends Entity {
|
||||
public class TippedArrowEntity extends AbstractArrowEntity {
|
||||
|
||||
public ArrowEntity(long entityId, long geyserId, EntityType entityType, Vector3f position, Vector3f motion, Vector3f rotation) {
|
||||
public TippedArrowEntity(long entityId, long geyserId, EntityType entityType, Vector3f position, Vector3f motion, Vector3f rotation) {
|
||||
super(entityId, geyserId, entityType, position, motion, rotation);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,48 @@
|
|||
/*
|
||||
* Copyright (c) 2019-2020 GeyserMC. http://geysermc.org
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*
|
||||
* @author GeyserMC
|
||||
* @link https://github.com/GeyserMC/Geyser
|
||||
*/
|
||||
|
||||
package org.geysermc.connector.entity;
|
||||
|
||||
import com.github.steveice10.mc.protocol.data.game.entity.metadata.EntityMetadata;
|
||||
import com.nukkitx.math.vector.Vector3f;
|
||||
import com.nukkitx.protocol.bedrock.data.EntityFlag;
|
||||
import org.geysermc.connector.entity.type.EntityType;
|
||||
import org.geysermc.connector.network.session.GeyserSession;
|
||||
|
||||
public class TridentEntity extends AbstractArrowEntity {
|
||||
|
||||
public TridentEntity(long entityId, long geyserId, EntityType entityType, Vector3f position, Vector3f motion, Vector3f rotation) {
|
||||
super(entityId, geyserId, entityType, position, motion, rotation);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateBedrockMetadata(EntityMetadata entityMetadata, GeyserSession session) {
|
||||
if (entityMetadata.getId() == 11) {
|
||||
metadata.getFlags().setFlag(EntityFlag.ENCHANTED, (boolean) entityMetadata.getValue());
|
||||
}
|
||||
|
||||
super.updateBedrockMetadata(entityMetadata, session);
|
||||
}
|
||||
}
|
|
@ -38,6 +38,7 @@ public enum AttributeType {
|
|||
MOVEMENT_SPEED("generic.movementSpeed", "minecraft:movement", 0f, 1024f, 0.1f),
|
||||
FLYING_SPEED("generic.flyingSpeed", "minecraft:movement", 0.0f, 1024.0f, 0.4000000059604645f),
|
||||
ATTACK_DAMAGE("generic.attackDamage", "minecraft:attack_damage", 0f, 2048f, 1f),
|
||||
HORSE_JUMP_STRENGTH("horse.jumpStrength", "minecraft:horse.jump_strength", 0.0f, 2.0f, 0.7f),
|
||||
|
||||
// Java Attributes
|
||||
ARMOR("generic.armor", null, 0f, 30f, 0f),
|
||||
|
|
|
@ -35,17 +35,42 @@ import org.geysermc.connector.network.session.GeyserSession;
|
|||
|
||||
public class ArmorStandEntity extends LivingEntity {
|
||||
|
||||
// These are used to store the state of the armour stand for use when handling invisibility
|
||||
private boolean isMarker = false;
|
||||
private boolean isInvisible = false;
|
||||
private boolean isSmall = false;
|
||||
|
||||
public ArmorStandEntity(long entityId, long geyserId, EntityType entityType, Vector3f position, Vector3f motion, Vector3f rotation) {
|
||||
super(entityId, geyserId, entityType, position, motion, rotation);
|
||||
}
|
||||
|
||||
@Override
|
||||
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
|
||||
if (!isMarker && isInvisible) {
|
||||
position = position.add(0d, entityType.getHeight() * (isSmall ? 0.55d : 1d), 0d);
|
||||
}
|
||||
|
||||
super.moveAbsolute(session, position, rotation, isOnGround, teleported);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateBedrockMetadata(EntityMetadata entityMetadata, GeyserSession session) {
|
||||
if (entityMetadata.getType() == MetadataType.BYTE) {
|
||||
if (entityMetadata.getId() == 0 && entityMetadata.getType() == MetadataType.BYTE) {
|
||||
byte xd = (byte) entityMetadata.getValue();
|
||||
|
||||
// Check if the armour stand is invisible and store accordingly
|
||||
if ((xd & 0x20) == 0x20) {
|
||||
metadata.put(EntityData.SCALE, 0.0f);
|
||||
isInvisible = true;
|
||||
}
|
||||
} else if (entityMetadata.getId() == 14 && entityMetadata.getType() == MetadataType.BYTE) {
|
||||
byte xd = (byte) entityMetadata.getValue();
|
||||
|
||||
// isSmall
|
||||
if ((xd & 0x01) == 0x01) {
|
||||
isSmall = true;
|
||||
|
||||
if (metadata.getFloat(EntityData.SCALE) != 0.55f && metadata.getFloat(EntityData.SCALE) != 0.0f) {
|
||||
metadata.put(EntityData.SCALE, 0.55f);
|
||||
}
|
||||
|
@ -60,9 +85,10 @@ public class ArmorStandEntity extends LivingEntity {
|
|||
}
|
||||
|
||||
// setMarker
|
||||
if ((xd & 0x10) == 0x10 && (metadata.get(EntityData.BOUNDING_BOX_WIDTH) != null && !metadata.get(EntityData.BOUNDING_BOX_WIDTH).equals(0.0f))) {
|
||||
if ((xd & 0x10) == 0x10 && (metadata.get(EntityData.BOUNDING_BOX_WIDTH) == null || !metadata.get(EntityData.BOUNDING_BOX_WIDTH).equals(0.0f))) {
|
||||
metadata.put(EntityData.BOUNDING_BOX_WIDTH, 0.0f);
|
||||
metadata.put(EntityData.BOUNDING_BOX_HEIGHT, 0.0f);
|
||||
isMarker = true;
|
||||
}
|
||||
}
|
||||
super.updateBedrockMetadata(entityMetadata, session);
|
||||
|
|
|
@ -27,25 +27,69 @@ package org.geysermc.connector.entity.living.animal.horse;
|
|||
|
||||
import com.github.steveice10.mc.protocol.data.game.entity.metadata.EntityMetadata;
|
||||
import com.nukkitx.math.vector.Vector3f;
|
||||
import com.nukkitx.protocol.bedrock.data.Attribute;
|
||||
import com.nukkitx.protocol.bedrock.data.EntityFlag;
|
||||
import com.nukkitx.protocol.bedrock.packet.UpdateAttributesPacket;
|
||||
import org.geysermc.connector.entity.attribute.AttributeType;
|
||||
import org.geysermc.connector.entity.living.animal.AnimalEntity;
|
||||
import org.geysermc.connector.entity.type.EntityType;
|
||||
import org.geysermc.connector.network.session.GeyserSession;
|
||||
import org.geysermc.connector.utils.AttributeUtils;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
public class AbstractHorseEntity extends AnimalEntity {
|
||||
|
||||
// For updating the horse visual easier
|
||||
private float health = 20f;
|
||||
|
||||
public AbstractHorseEntity(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() == 8) {
|
||||
health = (float) entityMetadata.getValue();
|
||||
updateBedrockAttributes(session);
|
||||
}
|
||||
|
||||
if (entityMetadata.getId() == 16) {
|
||||
byte xd = (byte) entityMetadata.getValue();
|
||||
metadata.getFlags().setFlag(EntityFlag.TAMED, (xd & 0x02) == 0x02);
|
||||
metadata.getFlags().setFlag(EntityFlag.SADDLED, (xd & 0x04) == 0x04);
|
||||
metadata.getFlags().setFlag(EntityFlag.EATING, (xd & 0x10) == 0x10);
|
||||
metadata.getFlags().setFlag(EntityFlag.STANDING, (xd & 0x20) == 0x20);
|
||||
}
|
||||
|
||||
// Needed to control horses
|
||||
metadata.getFlags().setFlag(EntityFlag.CAN_POWER_JUMP, true);
|
||||
metadata.getFlags().setFlag(EntityFlag.WASD_CONTROLLED, true);
|
||||
|
||||
super.updateBedrockMetadata(entityMetadata, session);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateBedrockAttributes(GeyserSession session) {
|
||||
if (!valid) return;
|
||||
|
||||
float maxHealth = attributes.containsKey(AttributeType.MAX_HEALTH) ? attributes.get(AttributeType.MAX_HEALTH).getValue() : 20f;
|
||||
|
||||
List<com.nukkitx.protocol.bedrock.data.Attribute> attributesLocal = new ArrayList<>();
|
||||
for (Map.Entry<AttributeType, org.geysermc.connector.entity.attribute.Attribute> entry : this.attributes.entrySet()) {
|
||||
if (!entry.getValue().getType().isBedrockAttribute())
|
||||
continue;
|
||||
|
||||
attributesLocal.add(AttributeUtils.getBedrockAttribute(entry.getValue()));
|
||||
}
|
||||
attributesLocal.add(new Attribute("minecraft:health", 0.0f, maxHealth, health, maxHealth));
|
||||
|
||||
UpdateAttributesPacket updateAttributesPacket = new UpdateAttributesPacket();
|
||||
updateAttributesPacket.setRuntimeEntityId(geyserId);
|
||||
updateAttributesPacket.setAttributes(attributesLocal);
|
||||
session.sendUpstreamPacket(updateAttributesPacket);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -28,6 +28,7 @@ package org.geysermc.connector.entity.living.animal.horse;
|
|||
import com.github.steveice10.mc.protocol.data.game.entity.metadata.EntityMetadata;
|
||||
import com.nukkitx.math.vector.Vector3f;
|
||||
import com.nukkitx.protocol.bedrock.data.EntityData;
|
||||
import com.nukkitx.protocol.bedrock.data.EntityFlag;
|
||||
import org.geysermc.connector.entity.type.EntityType;
|
||||
import org.geysermc.connector.network.session.GeyserSession;
|
||||
|
||||
|
@ -41,8 +42,9 @@ public class HorseEntity extends AbstractHorseEntity {
|
|||
public void updateBedrockMetadata(EntityMetadata entityMetadata, GeyserSession session) {
|
||||
if (entityMetadata.getId() == 18) {
|
||||
metadata.put(EntityData.VARIANT, (int) entityMetadata.getValue());
|
||||
metadata.put(EntityData.MARK_VARIANT, (((int) entityMetadata.getValue()) >> 8) % 5);
|
||||
}
|
||||
|
||||
super.updateBedrockMetadata(entityMetadata, session);
|
||||
}
|
||||
|
||||
}
|
|
@ -39,8 +39,8 @@ public class CreeperEntity extends MonsterEntity {
|
|||
|
||||
@Override
|
||||
public void updateBedrockMetadata(EntityMetadata entityMetadata, GeyserSession session) {
|
||||
if (entityMetadata.getId() == 15 && (int) entityMetadata.getValue() > 0) {
|
||||
metadata.getFlags().setFlag(EntityFlag.IGNITED, true);
|
||||
if (entityMetadata.getId() == 15) {
|
||||
metadata.getFlags().setFlag(EntityFlag.IGNITED, (int) entityMetadata.getValue() == 1);
|
||||
}
|
||||
if (entityMetadata.getId() == 16) {
|
||||
metadata.getFlags().setFlag(EntityFlag.POWERED, (boolean) entityMetadata.getValue());
|
||||
|
|
|
@ -0,0 +1,41 @@
|
|||
/*
|
||||
* Copyright (c) 2019-2020 GeyserMC. http://geysermc.org
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*
|
||||
* @author GeyserMC
|
||||
* @link https://github.com/GeyserMC/Geyser
|
||||
*
|
||||
*/
|
||||
|
||||
package org.geysermc.connector.entity.living.monster;
|
||||
|
||||
import com.nukkitx.math.vector.Vector3f;
|
||||
import com.nukkitx.protocol.bedrock.data.EntityFlag;
|
||||
import org.geysermc.connector.entity.type.EntityType;
|
||||
|
||||
public class ElderGuardianEntity extends GuardianEntity {
|
||||
|
||||
public ElderGuardianEntity(long entityId, long geyserId, EntityType entityType, Vector3f position, Vector3f motion, Vector3f rotation) {
|
||||
super(entityId, geyserId, entityType, position, motion, rotation);
|
||||
// Otherwise it just looks like a normal guardian but bigger
|
||||
metadata.getFlags().setFlag(EntityFlag.ELDER, true);
|
||||
}
|
||||
|
||||
}
|
|
@ -23,23 +23,17 @@
|
|||
* @link https://github.com/GeyserMC/Geyser
|
||||
*/
|
||||
|
||||
package org.geysermc.connector.network.translators;
|
||||
package org.geysermc.connector.entity.living.monster;
|
||||
|
||||
import com.github.steveice10.opennbt.tag.builtin.CompoundTag;
|
||||
import org.geysermc.connector.network.translators.item.ItemEntry;
|
||||
import com.nukkitx.math.vector.Vector3f;
|
||||
import com.nukkitx.protocol.bedrock.data.EntityData;
|
||||
import org.geysermc.connector.entity.type.EntityType;
|
||||
|
||||
public class NbtItemStackTranslator {
|
||||
public class GiantEntity extends MonsterEntity {
|
||||
|
||||
public void translateToBedrock(CompoundTag itemTag, ItemEntry itemEntry) {
|
||||
public GiantEntity(long entityId, long geyserId, EntityType entityType, Vector3f position, Vector3f motion, Vector3f rotation) {
|
||||
super(entityId, geyserId, entityType, position, motion, rotation);
|
||||
|
||||
metadata.put(EntityData.SCALE, 6f);
|
||||
}
|
||||
|
||||
public void translateToJava(CompoundTag itemTag, ItemEntry itemEntry) {
|
||||
|
||||
}
|
||||
|
||||
public boolean acceptItem(ItemEntry itemEntry) {
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
|
@ -64,6 +64,7 @@ public enum EntityType {
|
|||
PARROT(ParrotEntity.class, 30, 0.9f, 0.5f),
|
||||
DOLPHIN(WaterEntity.class, 31, 0.6f, 0.9f),
|
||||
ZOMBIE(ZombieEntity.class, 32, 1.8f, 0.6f, 0.6f, 1.62f),
|
||||
GIANT(GiantEntity.class, 32, 1.8f, 0.6f, 0.6f, 1.62f, "minecraft:zombie"),
|
||||
CREEPER(CreeperEntity.class, 33, 1.7f, 0.6f, 0.6f, 1.62f),
|
||||
SKELETON(AbstractSkeletonEntity.class, 34, 1.8f, 0.6f, 0.6f, 1.62f),
|
||||
SPIDER(SpiderEntity.class, 35, 0.9f, 1.4f, 1.4f, 1f),
|
||||
|
@ -81,7 +82,7 @@ public enum EntityType {
|
|||
HUSK(ZombieEntity.class, 47, 1.8f, 0.6f, 0.6f, 1.62f),
|
||||
WITHER_SKELETON(AbstractSkeletonEntity.class, 48, 2.4f, 0.7f),
|
||||
GUARDIAN(GuardianEntity.class, 49, 0.85f),
|
||||
ELDER_GUARDIAN(GuardianEntity.class, 50, 1.9975f),
|
||||
ELDER_GUARDIAN(ElderGuardianEntity.class, 50, 1.9975f),
|
||||
NPC(PlayerEntity.class, 51, 1.8f, 0.6f, 0.6f, 1.62f),
|
||||
WITHER(WitherEntity.class, 52, 3.5f, 0.9f),
|
||||
ENDER_DRAGON(EnderDragonEntity.class, 53, 4f, 13f),
|
||||
|
@ -98,45 +99,47 @@ public enum EntityType {
|
|||
TRIPOD_CAMERA(Entity.class, 62, 0f),
|
||||
PLAYER(PlayerEntity.class, 63, 1.8f, 0.6f, 0.6f, 1.62f),
|
||||
ITEM(ItemEntity.class, 64, 0.25f, 0.25f),
|
||||
TNT(TNTEntity.class, 65, 0.98f, 0.98f),
|
||||
PRIMED_TNT(TNTEntity.class, 65, 0.98f, 0.98f, 0.98f, 0f, "minecraft:tnt"),
|
||||
FALLING_BLOCK(FallingBlockEntity.class, 66, 0.98f, 0.98f),
|
||||
MOVING_BLOCK(Entity.class, 67, 0f),
|
||||
EXPERIENCE_BOTTLE(ThrowableEntity.class, 68, 0.25f, 0.25f, 0f, 0f, "minecraft:xp_bottle"),
|
||||
THROWN_EXP_BOTTLE(ThrowableEntity.class, 68, 0.25f, 0.25f, 0f, 0f, "minecraft:xp_bottle"),
|
||||
EXPERIENCE_ORB(ExpOrbEntity.class, 69, 0f, 0f, 0f, 0f, "minecraft:xp_orb"),
|
||||
EYE_OF_ENDER(Entity.class, 70, 0.25f),
|
||||
END_CRYSTAL(EnderCrystalEntity.class, 71, 0f, 0f, 0f, 0f, "minecraft:ender_crystal"),
|
||||
FIREWORK_ROCKET(Entity.class, 72, 0.25f),
|
||||
TRIDENT(ArrowEntity.class, 73, 0f),
|
||||
EYE_OF_ENDER(Entity.class, 70, 0.25f, 0.25f, 0f, 0f, "minecraft:eye_of_ender_signal"),
|
||||
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"),
|
||||
TRIDENT(TridentEntity.class, 73, 0f, 0f, 0f, 0f, "minecraft:thrown_trident"),
|
||||
TURTLE(AnimalEntity.class, 74, 0.4f, 1.2f),
|
||||
CAT(CatEntity.class, 75, 0.35f, 0.3f),
|
||||
SHULKER_BULLET(Entity.class, 76, 0.3125f),
|
||||
FISHING_BOBBER(FishingHookEntity.class, 77, 0f, 0f, 0f, 0f, "minecraft:fishing_hook"),
|
||||
CHALKBOARD(Entity.class, 78, 0f),
|
||||
DRAGON_FIREBALL(ItemedFireballEntity.class, 79, 1.0f),
|
||||
ARROW(ArrowEntity.class, 80, 0.25f, 0.25f),
|
||||
ARROW(TippedArrowEntity.class, 80, 0.25f, 0.25f),
|
||||
SPECTRAL_ARROW(AbstractArrowEntity.class, 80, 0.25f, 0.25f, 0.25f, 0f, "minecraft:arrow"),
|
||||
SNOWBALL(ThrowableEntity.class, 81, 0.25f),
|
||||
EGG(ThrowableEntity.class, 82, 0.25f),
|
||||
THROWN_EGG(ThrowableEntity.class, 82, 0.25f, 0.25f, 0.25f, 0f, "minecraft:egg"),
|
||||
PAINTING(PaintingEntity.class, 83, 0f),
|
||||
MINECART(MinecartEntity.class, 84, 0.7f, 0.98f),
|
||||
MINECART(MinecartEntity.class, 84, 0.7f, 0.98f, 0.98f, 0.35f),
|
||||
FIREBALL(ItemedFireballEntity.class, 85, 1.0f),
|
||||
POTION(ThrowableEntity.class, 86, 0.25f),
|
||||
ENDER_PEARL(ThrowableEntity.class, 87, 0.25f),
|
||||
LEASH_KNOT(Entity.class, 88, 0.5f, 0.375f),
|
||||
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"),
|
||||
LEASH_KNOT(LeashKnotEntity.class, 88, 0.5f, 0.375f),
|
||||
WITHER_SKULL(Entity.class, 89, 0.3125f),
|
||||
BOAT(Entity.class, 90, 0.7f, 1.6f, 1.6f, 0.35f),
|
||||
BOAT(BoatEntity.class, 90, 0.7f, 1.6f, 1.6f, 0.35f),
|
||||
WITHER_SKULL_DANGEROUS(Entity.class, 91, 0f),
|
||||
LIGHTNING_BOLT(Entity.class, 93, 0f),
|
||||
SMALL_FIREBALL(ItemedFireballEntity.class, 94, 0.3125f),
|
||||
AREA_EFFECT_CLOUD(AreaEffectCloudEntity.class, 95, 0.5f, 1.0f),
|
||||
HOPPER_MINECART(MinecartEntity.class, 96, 0.7f, 0.98f),
|
||||
TNT_MINECART(MinecartEntity.class, 97, 0.7f, 0.98f),
|
||||
CHEST_MINECART(MinecartEntity.class, 98, 0.7f, 0.98f),
|
||||
|
||||
COMMAND_BLOCK_MINECART(MinecartEntity.class, 100, 0.7f, 0.98f),
|
||||
MINECART_HOPPER(MinecartEntity.class, 96, 0.7f, 0.98f, 0.98f, 0.35f, "minecraft:hopper_minecart"),
|
||||
MINECART_TNT(MinecartEntity.class, 97, 0.7f, 0.98f, 0.98f, 0.35f, "minecraft:tnt_minecart"),
|
||||
MINECART_CHEST(MinecartEntity.class, 98, 0.7f, 0.98f, 0.98f, 0.35f, "minecraft:chest_minecart"),
|
||||
MINECART_FURNACE(FurnaceMinecartEntity.class, 98, 0.7f, 0.98f, 0.98f, 0.35f, "minecraft:minecart"),
|
||||
MINECART_SPAWNER(SpawnerMinecartEntity.class, 98, 0.7f, 0.98f, 0.98f, 0.35f, "minecraft:minecart"),
|
||||
MINECART_COMMAND_BLOCK(MinecartEntity.class, 100, 0.7f, 0.98f, 0.98f, 0.35f, "minecraft:command_block_minecart"),
|
||||
LINGERING_POTION(ThrowableEntity.class, 101, 0f),
|
||||
LLAMA_SPIT(Entity.class, 102, 0.25f),
|
||||
EVOKER_FANGS(Entity.class, 103, 0.8f, 0.5f),
|
||||
EVOKER(SpellcasterIllagerEntity.class, 104, 1.95f, 0.5f),
|
||||
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"),
|
||||
VEX(MonsterEntity.class, 105, 0.8f, 0.4f),
|
||||
ICE_BOMB(Entity.class, 106, 0f),
|
||||
BALLOON(Entity.class, 107, 0f), //TODO
|
||||
|
@ -159,6 +162,8 @@ public enum EntityType {
|
|||
*/
|
||||
ILLUSIONER(AbstractIllagerEntity.class, 114, 1.8f, 0.6f, 0.6f, 1.62f, "minecraft:pillager");
|
||||
|
||||
private static final EntityType[] VALUES = values();
|
||||
|
||||
private Class<? extends Entity> entityClass;
|
||||
private final int type;
|
||||
private final float height;
|
||||
|
@ -194,4 +199,14 @@ public enum EntityType {
|
|||
this.offset = offset + 0.00001f;
|
||||
this.identifier = identifier;
|
||||
}
|
||||
|
||||
public static EntityType getFromIdentifier(String identifier) {
|
||||
for (EntityType type : VALUES) {
|
||||
if (type.identifier.equals(identifier)) {
|
||||
return type;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -25,11 +25,12 @@
|
|||
|
||||
package org.geysermc.connector.network;
|
||||
|
||||
import com.github.steveice10.mc.protocol.data.status.ServerStatusInfo;
|
||||
import com.nukkitx.protocol.bedrock.BedrockPong;
|
||||
import com.nukkitx.protocol.bedrock.BedrockServerEventHandler;
|
||||
import com.nukkitx.protocol.bedrock.BedrockServerSession;
|
||||
|
||||
import com.github.steveice10.mc.protocol.data.message.Message;
|
||||
import com.nukkitx.protocol.bedrock.*;
|
||||
import io.netty.channel.ChannelHandlerContext;
|
||||
import io.netty.channel.socket.DatagramPacket;
|
||||
import org.geysermc.common.ping.GeyserPingInfo;
|
||||
import org.geysermc.connector.ping.IGeyserPingPassthrough;
|
||||
import org.geysermc.connector.GeyserConfiguration;
|
||||
import org.geysermc.connector.GeyserConnector;
|
||||
import org.geysermc.connector.network.session.GeyserSession;
|
||||
|
@ -39,7 +40,7 @@ import java.net.InetSocketAddress;
|
|||
|
||||
public class ConnectorServerEventHandler implements BedrockServerEventHandler {
|
||||
|
||||
private GeyserConnector connector;
|
||||
private final GeyserConnector connector;
|
||||
|
||||
public ConnectorServerEventHandler(GeyserConnector connector) {
|
||||
this.connector = connector;
|
||||
|
@ -56,29 +57,39 @@ public class ConnectorServerEventHandler implements BedrockServerEventHandler {
|
|||
connector.getLogger().debug(inetSocketAddress + " has pinged you!");
|
||||
|
||||
GeyserConfiguration config = connector.getConfig();
|
||||
ServerStatusInfo serverInfo = connector.getPassthroughThread().getInfo();
|
||||
|
||||
GeyserPingInfo pingInfo = null;
|
||||
if (config.isPassthroughMotd() || config.isPassthroughPlayerCounts()) {
|
||||
IGeyserPingPassthrough pingPassthrough = connector.getBootstrap().getGeyserPingPassthrough();
|
||||
pingInfo = pingPassthrough.getPingInformation();
|
||||
}
|
||||
|
||||
BedrockPong pong = new BedrockPong();
|
||||
pong.setEdition("MCPE");
|
||||
pong.setGameType("Default");
|
||||
pong.setNintendoLimited(false);
|
||||
pong.setProtocolVersion(GeyserConnector.BEDROCK_PACKET_CODEC.getProtocolVersion());
|
||||
pong.setVersion(GeyserConnector.BEDROCK_PACKET_CODEC.getMinecraftVersion());
|
||||
pong.setVersion(null); // Server tries to connect either way and it looks better
|
||||
pong.setIpv4Port(config.getBedrock().getPort());
|
||||
if (connector.getConfig().isPingPassthrough() && serverInfo != null) {
|
||||
String[] motd = MessageUtils.getBedrockMessage(serverInfo.getDescription()).split("\n");
|
||||
|
||||
if (config.isPassthroughMotd() && pingInfo != null && pingInfo.motd != null) {
|
||||
String[] motd = MessageUtils.getBedrockMessage(Message.fromString(pingInfo.motd)).split("\n");
|
||||
String mainMotd = motd[0]; // First line of the motd.
|
||||
String subMotd = (motd.length != 1) ? motd[1] : ""; // Second line of the motd if present, otherwise blank.
|
||||
|
||||
pong.setMotd(mainMotd.trim());
|
||||
pong.setSubMotd(subMotd.trim()); // Trimmed to shift it to the left, prevents the universe from collapsing on us just because we went 2 characters over the text box's limit.
|
||||
pong.setPlayerCount(serverInfo.getPlayerInfo().getOnlinePlayers());
|
||||
pong.setMaximumPlayerCount(serverInfo.getPlayerInfo().getMaxPlayers());
|
||||
} else {
|
||||
pong.setMotd(config.getBedrock().getMotd1());
|
||||
pong.setSubMotd(config.getBedrock().getMotd2());
|
||||
}
|
||||
|
||||
if (config.isPassthroughPlayerCounts() && pingInfo != null) {
|
||||
pong.setPlayerCount(pingInfo.currentPlayerCount);
|
||||
pong.setMaximumPlayerCount(pingInfo.maxPlayerCount);
|
||||
} else {
|
||||
pong.setPlayerCount(connector.getPlayers().size());
|
||||
pong.setMaximumPlayerCount(config.getMaxPlayers());
|
||||
pong.setMotd(config.getBedrock().getMotd1());
|
||||
pong.setMotd(config.getBedrock().getMotd2());
|
||||
}
|
||||
|
||||
//Bedrock will not even attempt a connection if the client thinks the server is full
|
||||
|
@ -105,4 +116,9 @@ public class ConnectorServerEventHandler implements BedrockServerEventHandler {
|
|||
});
|
||||
bedrockServerSession.setPacketCodec(GeyserConnector.BEDROCK_PACKET_CODEC);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onUnhandledDatagram(ChannelHandlerContext ctx, DatagramPacket packet) {
|
||||
new QueryPacketHandler(connector, packet.sender(), packet.content());
|
||||
}
|
||||
}
|
|
@ -0,0 +1,287 @@
|
|||
/*
|
||||
* Copyright (c) 2019-2020 GeyserMC. http://geysermc.org
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*
|
||||
* @author GeyserMC
|
||||
* @link https://github.com/GeyserMC/Geyser
|
||||
*
|
||||
*/
|
||||
|
||||
package org.geysermc.connector.network;
|
||||
|
||||
import com.github.steveice10.mc.protocol.data.message.Message;
|
||||
import io.netty.buffer.ByteBuf;
|
||||
import io.netty.buffer.ByteBufAllocator;
|
||||
import org.geysermc.common.ping.GeyserPingInfo;
|
||||
import org.geysermc.connector.GeyserConnector;
|
||||
import org.geysermc.connector.utils.MessageUtils;
|
||||
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.net.InetAddress;
|
||||
import java.net.InetSocketAddress;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.security.MessageDigest;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
import java.util.Arrays;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Random;
|
||||
import java.util.concurrent.ThreadLocalRandom;
|
||||
|
||||
public class QueryPacketHandler {
|
||||
|
||||
public static final byte HANDSHAKE = 0x09;
|
||||
public static final byte STATISTICS = 0x00;
|
||||
|
||||
private GeyserConnector connector;
|
||||
private InetSocketAddress sender;
|
||||
private byte type;
|
||||
private int sessionId;
|
||||
private byte[] token;
|
||||
|
||||
/**
|
||||
* The Query packet handler instance
|
||||
*
|
||||
* @param connector Geyser Connector
|
||||
* @param sender The Sender IP/Port for the Query
|
||||
* @param buffer The Query data
|
||||
*/
|
||||
public QueryPacketHandler(GeyserConnector connector, InetSocketAddress sender, ByteBuf buffer) {
|
||||
if(!isQueryPacket(buffer))
|
||||
return;
|
||||
|
||||
this.connector = connector;
|
||||
this.sender = sender;
|
||||
this.type = buffer.readByte();
|
||||
this.sessionId = buffer.readInt();
|
||||
|
||||
regenerateToken();
|
||||
handle();
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks the packet is in fact a query packet
|
||||
*
|
||||
* @param buffer Query data
|
||||
* @return if the packet is a query packet
|
||||
*/
|
||||
private boolean isQueryPacket(ByteBuf buffer) {
|
||||
return (buffer.readableBytes() >= 2) ? buffer.readUnsignedShort() == 0xFEFD : false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles the query
|
||||
*/
|
||||
private void handle() {
|
||||
switch (type) {
|
||||
case HANDSHAKE:
|
||||
sendToken();
|
||||
case STATISTICS:
|
||||
sendQueryData();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sends the token to the sender
|
||||
*/
|
||||
private void sendToken() {
|
||||
ByteBuf reply = ByteBufAllocator.DEFAULT.ioBuffer(10);
|
||||
reply.writeByte(HANDSHAKE);
|
||||
reply.writeInt(sessionId);
|
||||
reply.writeBytes(getTokenString(this.token, this.sender.getAddress()));
|
||||
reply.writeByte(0);
|
||||
|
||||
sendPacket(reply);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sends the query data to the sender
|
||||
*/
|
||||
private void sendQueryData() {
|
||||
ByteBuf reply = ByteBufAllocator.DEFAULT.ioBuffer(64);
|
||||
reply.writeByte(STATISTICS);
|
||||
reply.writeInt(sessionId);
|
||||
|
||||
// Game Info
|
||||
reply.writeBytes(getGameData());
|
||||
|
||||
// Players
|
||||
reply.writeBytes(getPlayers());
|
||||
|
||||
sendPacket(reply);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the game data for the query
|
||||
*
|
||||
* @return the game data for the query
|
||||
*/
|
||||
private byte[] getGameData() {
|
||||
ByteArrayOutputStream query = new ByteArrayOutputStream();
|
||||
|
||||
GeyserPingInfo pingInfo = null;
|
||||
String motd;
|
||||
String currentPlayerCount;
|
||||
String maxPlayerCount;
|
||||
|
||||
if (connector.getConfig().isPassthroughMotd() || connector.getConfig().isPassthroughPlayerCounts()) {
|
||||
pingInfo = connector.getBootstrap().getGeyserPingPassthrough().getPingInformation();
|
||||
}
|
||||
|
||||
if (connector.getConfig().isPassthroughMotd() && pingInfo != null) {
|
||||
String[] javaMotd = MessageUtils.getBedrockMessage(Message.fromString(pingInfo.motd)).split("\n");
|
||||
motd = javaMotd[0].trim(); // First line of the motd.
|
||||
} else {
|
||||
motd = connector.getConfig().getBedrock().getMotd1();
|
||||
}
|
||||
|
||||
// If passthrough player counts is enabled lets get players from the server
|
||||
if (connector.getConfig().isPassthroughPlayerCounts() && pingInfo != null) {
|
||||
currentPlayerCount = String.valueOf(pingInfo.currentPlayerCount);
|
||||
maxPlayerCount = String.valueOf(pingInfo.maxPlayerCount);
|
||||
} else {
|
||||
currentPlayerCount = String.valueOf(connector.getPlayers().size());
|
||||
maxPlayerCount = String.valueOf(connector.getConfig().getMaxPlayers());
|
||||
}
|
||||
|
||||
// Create a hashmap of all game data needed in the query
|
||||
Map<String, String> gameData = new HashMap<String, String>();
|
||||
gameData.put("hostname", motd);
|
||||
gameData.put("gametype", "SMP");
|
||||
gameData.put("game_id", "MINECRAFT");
|
||||
gameData.put("version", GeyserConnector.BEDROCK_PACKET_CODEC.getMinecraftVersion());
|
||||
gameData.put("plugins", "");
|
||||
gameData.put("map", GeyserConnector.NAME);
|
||||
gameData.put("numplayers", currentPlayerCount);
|
||||
gameData.put("maxplayers", maxPlayerCount);
|
||||
gameData.put("hostport", String.valueOf(connector.getConfig().getBedrock().getPort()));
|
||||
gameData.put("hostip", connector.getConfig().getBedrock().getAddress());
|
||||
|
||||
try {
|
||||
// Blank Buffer Bytes
|
||||
query.write("GeyserMC".getBytes());
|
||||
query.write((byte) 0x00);
|
||||
query.write((byte) 0x80);
|
||||
query.write((byte) 0x00);
|
||||
|
||||
// Fills the game data
|
||||
for(Map.Entry<String, String> entry : gameData.entrySet()) {
|
||||
query.write(entry.getKey().getBytes());
|
||||
query.write((byte) 0x00);
|
||||
query.write(entry.getValue().getBytes());
|
||||
query.write((byte) 0x00);
|
||||
}
|
||||
|
||||
// Final byte to show the end of the game data
|
||||
query.write(new byte[] { 0x00, 0x01 });
|
||||
return query.toByteArray();
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
return new byte[0];
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate a byte[] storing the player names
|
||||
*
|
||||
* @return The byte[] representation of players
|
||||
*/
|
||||
private byte[] getPlayers() {
|
||||
ByteArrayOutputStream query = new ByteArrayOutputStream();
|
||||
|
||||
GeyserPingInfo pingInfo = null;
|
||||
if (connector.getConfig().isPassthroughMotd() || connector.getConfig().isPassthroughPlayerCounts()) {
|
||||
pingInfo = connector.getBootstrap().getGeyserPingPassthrough().getPingInformation();
|
||||
}
|
||||
|
||||
try {
|
||||
// Start the player section
|
||||
query.write("player_".getBytes());
|
||||
query.write(new byte[] { 0x00, 0x00 });
|
||||
|
||||
// Fill player names
|
||||
if(pingInfo != null) {
|
||||
for (String username : pingInfo.getPlayers()) {
|
||||
query.write(username.getBytes());
|
||||
query.write((byte) 0x00);
|
||||
}
|
||||
}
|
||||
|
||||
// Final byte to show the end of the player data
|
||||
query.write((byte) 0x00);
|
||||
return query.toByteArray();
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
return new byte[0];
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sends a packet to the sender
|
||||
*
|
||||
* @param data packet data
|
||||
*/
|
||||
private void sendPacket(ByteBuf data) {
|
||||
connector.getBedrockServer().getRakNet().send(sender, data);
|
||||
}
|
||||
|
||||
/**
|
||||
* Regenerates a token
|
||||
*/
|
||||
public void regenerateToken() {
|
||||
byte[] token = new byte[16];
|
||||
for (int i = 0; i < 16; i++) {
|
||||
token[i] = (byte) new Random().nextInt(255);
|
||||
}
|
||||
|
||||
this.token = token;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets an MD5 token for the current IP/Port.
|
||||
* This should reset every 30 seconds but a new one is generated per instance
|
||||
* Seems wasteful to code something in to clear it when it has no use.
|
||||
*
|
||||
* @param token the token
|
||||
* @param address the address
|
||||
* @return an MD5 token for the current IP/Port
|
||||
*/
|
||||
public static byte[] getTokenString(byte[] token, InetAddress address) {
|
||||
try {
|
||||
// Generate an MD5 hash from the address
|
||||
MessageDigest digest = MessageDigest.getInstance("MD5");
|
||||
digest.update(address.toString().getBytes(StandardCharsets.UTF_8));
|
||||
digest.update(token);
|
||||
|
||||
// Get the first 4 bytes of the digest
|
||||
byte[] digestBytes = Arrays.copyOf(digest.digest(), 4);
|
||||
|
||||
// Convert the bytes to a buffer
|
||||
ByteBuffer byteBuffer = ByteBuffer.wrap(digestBytes);
|
||||
|
||||
// Turn the number into a null terminated string
|
||||
return (byteBuffer.getInt() + "\0").getBytes();
|
||||
} catch (NoSuchAlgorithmException e) {
|
||||
return (ByteBuffer.allocate(4).putInt(ThreadLocalRandom.current().nextInt()).getInt() + "\0").getBytes();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -31,7 +31,7 @@ import org.geysermc.common.AuthType;
|
|||
import org.geysermc.connector.GeyserConfiguration;
|
||||
import org.geysermc.connector.GeyserConnector;
|
||||
import org.geysermc.connector.network.session.GeyserSession;
|
||||
import org.geysermc.connector.network.translators.Registry;
|
||||
import org.geysermc.connector.network.translators.PacketTranslatorRegistry;
|
||||
import org.geysermc.connector.utils.LoginEncryptionUtils;
|
||||
|
||||
public class UpstreamPacketHandler extends LoggingPacketHandler {
|
||||
|
@ -41,7 +41,7 @@ public class UpstreamPacketHandler extends LoggingPacketHandler {
|
|||
}
|
||||
|
||||
private boolean translateAndDefault(BedrockPacket packet) {
|
||||
return Registry.BEDROCK.translate(packet.getClass(), packet, session);
|
||||
return PacketTranslatorRegistry.BEDROCK_TRANSLATOR.translate(packet.getClass(), packet, session);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -110,15 +110,19 @@ public class UpstreamPacketHandler extends LoggingPacketHandler {
|
|||
}
|
||||
|
||||
@Override
|
||||
public boolean handle(MovePlayerPacket packet) {
|
||||
public boolean handle(SetLocalPlayerAsInitializedPacket packet) {
|
||||
if (!session.isLoggedIn() && !session.isLoggingIn() && session.getConnector().getAuthType() == AuthType.ONLINE) {
|
||||
// TODO it is safer to key authentication on something that won't change (UUID, not username)
|
||||
if (!couldLoginUserByName(session.getAuthData().getName())) {
|
||||
LoginEncryptionUtils.showLoginWindow(session);
|
||||
}
|
||||
// else we were able to log the user in
|
||||
return true;
|
||||
}
|
||||
return translateAndDefault(packet);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean handle(MovePlayerPacket packet) {
|
||||
if (session.isLoggingIn()) {
|
||||
session.sendMessage("Please wait until you are logged in...");
|
||||
}
|
||||
|
|
|
@ -60,18 +60,21 @@ import org.geysermc.common.AuthType;
|
|||
import org.geysermc.common.window.FormWindow;
|
||||
import org.geysermc.connector.GeyserConnector;
|
||||
import org.geysermc.connector.command.CommandSender;
|
||||
import org.geysermc.connector.entity.Entity;
|
||||
import org.geysermc.connector.entity.PlayerEntity;
|
||||
import org.geysermc.connector.inventory.PlayerInventory;
|
||||
import org.geysermc.connector.network.remote.RemoteServer;
|
||||
import org.geysermc.connector.network.session.auth.AuthData;
|
||||
import org.geysermc.connector.network.session.auth.BedrockClientData;
|
||||
import org.geysermc.connector.network.session.cache.*;
|
||||
import org.geysermc.connector.network.translators.Registry;
|
||||
import org.geysermc.connector.network.translators.BiomeTranslator;
|
||||
import org.geysermc.connector.network.translators.EntityIdentifierRegistry;
|
||||
import org.geysermc.connector.network.translators.PacketTranslatorRegistry;
|
||||
import org.geysermc.connector.network.translators.item.ItemRegistry;
|
||||
import org.geysermc.connector.network.translators.world.block.BlockTranslator;
|
||||
import org.geysermc.connector.utils.ChunkUtils;
|
||||
import org.geysermc.connector.utils.LocaleUtils;
|
||||
import org.geysermc.connector.utils.SkinUtils;
|
||||
import org.geysermc.connector.utils.Toolbox;
|
||||
import org.geysermc.floodgate.util.BedrockData;
|
||||
import org.geysermc.floodgate.util.EncryptionUtil;
|
||||
|
||||
|
@ -159,9 +162,15 @@ public class GeyserSession implements CommandSender {
|
|||
private boolean manyDimPackets = false;
|
||||
private ServerRespawnPacket lastDimPacket = null;
|
||||
|
||||
@Setter
|
||||
private Entity ridingVehicleEntity;
|
||||
|
||||
@Setter
|
||||
private int craftSlot = 0;
|
||||
|
||||
@Setter
|
||||
private long lastWindowCloseTime = 0;
|
||||
|
||||
@Setter
|
||||
private VillagerTrade[] villagerTrades;
|
||||
|
||||
|
@ -195,16 +204,16 @@ public class GeyserSession implements CommandSender {
|
|||
ChunkUtils.sendEmptyChunks(this, playerEntity.getPosition().toInt(), 0, false);
|
||||
|
||||
BiomeDefinitionListPacket biomeDefinitionListPacket = new BiomeDefinitionListPacket();
|
||||
biomeDefinitionListPacket.setTag(Toolbox.BIOMES);
|
||||
biomeDefinitionListPacket.setTag(BiomeTranslator.BIOMES);
|
||||
upstream.sendPacket(biomeDefinitionListPacket);
|
||||
|
||||
AvailableEntityIdentifiersPacket entityPacket = new AvailableEntityIdentifiersPacket();
|
||||
entityPacket.setTag(Toolbox.ENTITY_IDENTIFIERS);
|
||||
entityPacket.setTag(EntityIdentifierRegistry.ENTITY_IDENTIFIERS);
|
||||
upstream.sendPacket(entityPacket);
|
||||
|
||||
InventoryContentPacket creativePacket = new InventoryContentPacket();
|
||||
creativePacket.setContainerId(ContainerId.CREATIVE);
|
||||
creativePacket.setContents(Toolbox.CREATIVE_ITEMS);
|
||||
creativePacket.setContents(ItemRegistry.CREATIVE_ITEMS);
|
||||
upstream.sendPacket(creativePacket);
|
||||
|
||||
PlayStatusPacket playStatusPacket = new PlayStatusPacket();
|
||||
|
@ -212,6 +221,17 @@ public class GeyserSession implements CommandSender {
|
|||
upstream.sendPacket(playStatusPacket);
|
||||
}
|
||||
|
||||
public void fetchOurSkin(PlayerListPacket.Entry entry) {
|
||||
PlayerSkinPacket playerSkinPacket = new PlayerSkinPacket();
|
||||
playerSkinPacket.setUuid(authData.getUUID());
|
||||
playerSkinPacket.setSkin(entry.getSkin());
|
||||
playerSkinPacket.setOldSkinName("OldName");
|
||||
playerSkinPacket.setNewSkinName("NewName");
|
||||
playerSkinPacket.setTrustedSkin(true);
|
||||
upstream.sendPacket(playerSkinPacket);
|
||||
getConnector().getLogger().debug("Sending skin for " + playerEntity.getUsername() + " " + authData.getUUID());
|
||||
}
|
||||
|
||||
public void login() {
|
||||
if (connector.getAuthType() != AuthType.ONLINE) {
|
||||
connector.getLogger().info(
|
||||
|
@ -335,7 +355,7 @@ public class GeyserSession implements CommandSender {
|
|||
lastDimPacket = event.getPacket();
|
||||
return;
|
||||
} else if (lastDimPacket != null) {
|
||||
Registry.JAVA.translate(lastDimPacket.getClass(), lastDimPacket, GeyserSession.this);
|
||||
PacketTranslatorRegistry.JAVA_TRANSLATOR.translate(lastDimPacket.getClass(), lastDimPacket, GeyserSession.this);
|
||||
lastDimPacket = null;
|
||||
}
|
||||
|
||||
|
@ -351,9 +371,17 @@ public class GeyserSession implements CommandSender {
|
|||
}
|
||||
}
|
||||
|
||||
Registry.JAVA.translate(event.getPacket().getClass(), event.getPacket(), GeyserSession.this);
|
||||
PacketTranslatorRegistry.JAVA_TRANSLATOR.translate(event.getPacket().getClass(), event.getPacket(), GeyserSession.this);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void packetError(PacketErrorEvent event) {
|
||||
connector.getLogger().warning("Downstream packet error! " + event.getCause().getMessage());
|
||||
if (connector.getConfig().isDebugMode())
|
||||
event.getCause().printStackTrace();
|
||||
event.setSuppress(true);
|
||||
}
|
||||
});
|
||||
|
||||
downstream.getSession().connect();
|
||||
|
@ -487,7 +515,7 @@ public class GeyserSession implements CommandSender {
|
|||
startGamePacket.setEnchantmentSeed(0);
|
||||
startGamePacket.setMultiplayerCorrelationId("");
|
||||
startGamePacket.setBlockPalette(BlockTranslator.BLOCKS);
|
||||
startGamePacket.setItemEntries(Toolbox.ITEMS);
|
||||
startGamePacket.setItemEntries(ItemRegistry.ITEMS);
|
||||
startGamePacket.setVanillaVersion("*");
|
||||
// startGamePacket.setMovementServerAuthoritative(true);
|
||||
upstream.sendPacket(startGamePacket);
|
||||
|
|
|
@ -104,10 +104,13 @@ public class BossBar {
|
|||
addEntityPacket.setRuntimeEntityId(entityId);
|
||||
addEntityPacket.setIdentifier("minecraft:creeper");
|
||||
addEntityPacket.setEntityType(33);
|
||||
addEntityPacket.setPosition(session.getPlayerEntity().getPosition());
|
||||
addEntityPacket.setPosition(session.getPlayerEntity().getPosition().sub(0D, -10D, 0D));
|
||||
addEntityPacket.setRotation(Vector3f.ZERO);
|
||||
addEntityPacket.setMotion(Vector3f.ZERO);
|
||||
addEntityPacket.getMetadata().put(EntityData.SCALE, 0.01F); // scale = 0 doesn't work?
|
||||
addEntityPacket.getMetadata()
|
||||
.putFloat(EntityData.SCALE, 0F)
|
||||
.putFloat(EntityData.BOUNDING_BOX_WIDTH, 0F)
|
||||
.putFloat(EntityData.BOUNDING_BOX_HEIGHT, 0F);
|
||||
|
||||
session.sendUpstreamPacket(addEntityPacket);
|
||||
}
|
||||
|
|
|
@ -26,8 +26,6 @@
|
|||
package org.geysermc.connector.network.session.cache;
|
||||
|
||||
import it.unimi.dsi.fastutil.longs.*;
|
||||
import it.unimi.dsi.fastutil.objects.Object2LongMap;
|
||||
import it.unimi.dsi.fastutil.objects.Object2LongOpenHashMap;
|
||||
import it.unimi.dsi.fastutil.objects.ObjectOpenHashSet;
|
||||
import lombok.Getter;
|
||||
import org.geysermc.connector.entity.Entity;
|
||||
|
@ -49,6 +47,7 @@ public class EntityCache {
|
|||
private Long2LongMap entityIdTranslations = Long2LongMaps.synchronize(new Long2LongOpenHashMap());
|
||||
private Map<UUID, PlayerEntity> playerEntities = Collections.synchronizedMap(new HashMap<>());
|
||||
private Map<UUID, BossBar> bossBars = Collections.synchronizedMap(new HashMap<>());
|
||||
private Long2LongMap cachedPlayerEntityLinks = Long2LongMaps.synchronize(new Long2LongOpenHashMap());
|
||||
|
||||
@Getter
|
||||
private AtomicLong nextEntityId = new AtomicLong(2L);
|
||||
|
@ -148,4 +147,12 @@ public class EntityCache {
|
|||
playerEntities = null;
|
||||
bossBars = null;
|
||||
}
|
||||
|
||||
public long getCachedPlayerEntityLink(long playerId) {
|
||||
return cachedPlayerEntityLinks.getOrDefault(playerId, -1);
|
||||
}
|
||||
|
||||
public void addCachedPlayerEntityLink(long playerId, long linkedEntityId) {
|
||||
cachedPlayerEntityLinks.put(playerId, linkedEntityId);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,14 +1,72 @@
|
|||
/*
|
||||
* Copyright (c) 2019-2020 GeyserMC. http://geysermc.org
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*
|
||||
* @author GeyserMC
|
||||
* @link https://github.com/GeyserMC/Geyser
|
||||
*
|
||||
*/
|
||||
|
||||
package org.geysermc.connector.network.translators;
|
||||
|
||||
import com.nukkitx.nbt.NbtUtils;
|
||||
import com.nukkitx.nbt.stream.NBTInputStream;
|
||||
import com.nukkitx.nbt.tag.CompoundTag;
|
||||
import org.geysermc.connector.GeyserConnector;
|
||||
import org.geysermc.connector.utils.FileUtils;
|
||||
|
||||
import java.io.InputStream;
|
||||
import java.util.Arrays;
|
||||
|
||||
//Based off of ProtocolSupport's LegacyBiomeData.java https://github.com/ProtocolSupport/ProtocolSupport/blob/b2cad35977f3fcb65bee57b9e14fc9c975f71d32/src/protocolsupport/protocol/typeremapper/legacy/LegacyBiomeData.java
|
||||
//Array index formula by https://wiki.vg/Chunk_Format
|
||||
|
||||
// Based off of ProtocolSupport's LegacyBiomeData.java:
|
||||
// https://github.com/ProtocolSupport/ProtocolSupport/blob/b2cad35977f3fcb65bee57b9e14fc9c975f71d32/src/protocolsupport/protocol/typeremapper/legacy/LegacyBiomeData.java
|
||||
// Array index formula by https://wiki.vg/Chunk_Format
|
||||
public class BiomeTranslator {
|
||||
|
||||
public static final CompoundTag BIOMES;
|
||||
|
||||
private BiomeTranslator() {
|
||||
}
|
||||
|
||||
public static void init() {
|
||||
// no-op
|
||||
}
|
||||
|
||||
static {
|
||||
/* Load biomes */
|
||||
InputStream stream = FileUtils.getResource("bedrock/biome_definitions.dat");
|
||||
|
||||
CompoundTag biomesTag;
|
||||
|
||||
try (NBTInputStream biomenbtInputStream = NbtUtils.createNetworkReader(stream)){
|
||||
biomesTag = (CompoundTag) biomenbtInputStream.readTag();
|
||||
BIOMES = biomesTag;
|
||||
} catch (Exception ex) {
|
||||
GeyserConnector.getInstance().getLogger().warning("Failed to get biomes from biome definitions, is there something wrong with the file?");
|
||||
throw new AssertionError(ex);
|
||||
}
|
||||
}
|
||||
|
||||
public static byte[] toBedrockBiome(int[] biomeData) {
|
||||
byte[] bedrockData = new byte[256];
|
||||
if(biomeData == null) {
|
||||
if (biomeData == null) {
|
||||
return bedrockData;
|
||||
}
|
||||
|
||||
|
@ -24,12 +82,12 @@ public class BiomeTranslator {
|
|||
return bedrockData;
|
||||
}
|
||||
|
||||
protected static void fillArray(int z, int x, byte[] legacyBiomeData, int biomeId) {
|
||||
private static void fillArray(int z, int x, byte[] legacyBiomeData, int biomeId) {
|
||||
int offset = (z << 4) | x;
|
||||
Arrays.fill(legacyBiomeData, offset, offset + 4, (byte) biomeId);
|
||||
}
|
||||
|
||||
protected static byte biomeID(int[] biomeData, int x, int z) {
|
||||
private static byte biomeID(int[] biomeData, int x, int z) {
|
||||
return (byte) biomeData[((z >> 2) & 3) << 2 | ((x >> 2) & 3)];
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,60 @@
|
|||
/*
|
||||
* Copyright (c) 2019-2020 GeyserMC. http://geysermc.org
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*
|
||||
* @author GeyserMC
|
||||
* @link https://github.com/GeyserMC/Geyser
|
||||
*
|
||||
*/
|
||||
|
||||
package org.geysermc.connector.network.translators;
|
||||
|
||||
import com.nukkitx.nbt.NbtUtils;
|
||||
import com.nukkitx.nbt.stream.NBTInputStream;
|
||||
import com.nukkitx.nbt.tag.CompoundTag;
|
||||
import org.geysermc.connector.utils.FileUtils;
|
||||
|
||||
import java.io.InputStream;
|
||||
|
||||
/**
|
||||
* Registry for entity identifiers.
|
||||
*/
|
||||
public class EntityIdentifierRegistry {
|
||||
|
||||
public static CompoundTag ENTITY_IDENTIFIERS;
|
||||
|
||||
private EntityIdentifierRegistry() {
|
||||
}
|
||||
|
||||
public static void init() {
|
||||
// no-op
|
||||
}
|
||||
|
||||
static {
|
||||
/* Load entity identifiers */
|
||||
InputStream stream = FileUtils.getResource("bedrock/entity_identifiers.dat");
|
||||
|
||||
try (NBTInputStream nbtInputStream = NbtUtils.createNetworkReader(stream)) {
|
||||
ENTITY_IDENTIFIERS = (CompoundTag) nbtInputStream.readTag();
|
||||
} catch (Exception e) {
|
||||
throw new AssertionError("Unable to get entities from entity identifiers", e);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,250 +0,0 @@
|
|||
/*
|
||||
* Copyright (c) 2019-2020 GeyserMC. http://geysermc.org
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*
|
||||
* @author GeyserMC
|
||||
* @link https://github.com/GeyserMC/Geyser
|
||||
*/
|
||||
|
||||
package org.geysermc.connector.network.translators;
|
||||
|
||||
import com.github.steveice10.mc.protocol.data.game.entity.metadata.ItemStack;
|
||||
import com.github.steveice10.mc.protocol.data.message.Message;
|
||||
import com.github.steveice10.opennbt.tag.builtin.*;
|
||||
import com.nukkitx.nbt.tag.CompoundTag;
|
||||
import com.nukkitx.nbt.tag.Tag;
|
||||
import com.nukkitx.protocol.bedrock.data.ItemData;
|
||||
import org.geysermc.connector.network.translators.item.ItemEntry;
|
||||
import org.geysermc.connector.utils.MessageUtils;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
public abstract class ItemStackTranslator {
|
||||
|
||||
public ItemData translateToBedrock(ItemStack itemStack, ItemEntry itemEntry) {
|
||||
if (itemStack == null) {
|
||||
return ItemData.AIR;
|
||||
}
|
||||
if (itemStack.getNbt() == null) {
|
||||
return ItemData.of(itemEntry.getBedrockId(), (short) itemEntry.getBedrockData(), itemStack.getAmount());
|
||||
}
|
||||
return ItemData.of(itemEntry.getBedrockId(), (short) itemEntry.getBedrockData(), itemStack.getAmount(), this.translateNbtToBedrock(itemStack.getNbt()));
|
||||
}
|
||||
|
||||
public ItemStack translateToJava(ItemData itemData, ItemEntry itemEntry) {
|
||||
if (itemData == null) return null;
|
||||
if (itemData.getTag() == null) {
|
||||
return new ItemStack(itemEntry.getJavaId(), itemData.getCount(), new com.github.steveice10.opennbt.tag.builtin.CompoundTag(""));
|
||||
}
|
||||
return new ItemStack(itemEntry.getJavaId(), itemData.getCount(), this.translateToJavaNBT(itemData.getTag()));
|
||||
}
|
||||
|
||||
public abstract List<ItemEntry> getAppliedItems();
|
||||
|
||||
public CompoundTag translateNbtToBedrock(com.github.steveice10.opennbt.tag.builtin.CompoundTag tag) {
|
||||
Map<String, Tag<?>> javaValue = new HashMap<String, Tag<?>>();
|
||||
if (tag.getValue() != null && !tag.getValue().isEmpty()) {
|
||||
for (String str : tag.getValue().keySet()) {
|
||||
com.github.steveice10.opennbt.tag.builtin.Tag javaTag = tag.get(str);
|
||||
com.nukkitx.nbt.tag.Tag translatedTag = translateToBedrockNBT(javaTag);
|
||||
if (translatedTag == null)
|
||||
continue;
|
||||
|
||||
javaValue.put(translatedTag.getName(), translatedTag);
|
||||
}
|
||||
}
|
||||
|
||||
com.nukkitx.nbt.tag.CompoundTag bedrockTag = new com.nukkitx.nbt.tag.CompoundTag(tag.getName(), javaValue);
|
||||
return bedrockTag;
|
||||
}
|
||||
|
||||
private com.nukkitx.nbt.tag.Tag translateToBedrockNBT(com.github.steveice10.opennbt.tag.builtin.Tag tag) {
|
||||
if (tag instanceof ByteArrayTag) {
|
||||
ByteArrayTag byteArrayTag = (ByteArrayTag) tag;
|
||||
return new com.nukkitx.nbt.tag.ByteArrayTag(byteArrayTag.getName(), byteArrayTag.getValue());
|
||||
}
|
||||
|
||||
if (tag instanceof ByteTag) {
|
||||
ByteTag byteTag = (ByteTag) tag;
|
||||
return new com.nukkitx.nbt.tag.ByteTag(byteTag.getName(), byteTag.getValue());
|
||||
}
|
||||
|
||||
if (tag instanceof DoubleTag) {
|
||||
DoubleTag doubleTag = (DoubleTag) tag;
|
||||
return new com.nukkitx.nbt.tag.DoubleTag(doubleTag.getName(), doubleTag.getValue());
|
||||
}
|
||||
|
||||
if (tag instanceof FloatTag) {
|
||||
FloatTag floatTag = (FloatTag) tag;
|
||||
return new com.nukkitx.nbt.tag.FloatTag(floatTag.getName(), floatTag.getValue());
|
||||
}
|
||||
|
||||
if (tag instanceof IntArrayTag) {
|
||||
IntArrayTag intArrayTag = (IntArrayTag) tag;
|
||||
return new com.nukkitx.nbt.tag.IntArrayTag(intArrayTag.getName(), intArrayTag.getValue());
|
||||
}
|
||||
|
||||
if (tag instanceof IntTag) {
|
||||
IntTag intTag = (IntTag) tag;
|
||||
return new com.nukkitx.nbt.tag.IntTag(intTag.getName(), intTag.getValue());
|
||||
}
|
||||
|
||||
if (tag instanceof LongArrayTag) {
|
||||
LongArrayTag longArrayTag = (LongArrayTag) tag;
|
||||
return new com.nukkitx.nbt.tag.LongArrayTag(longArrayTag.getName(), longArrayTag.getValue());
|
||||
}
|
||||
|
||||
if (tag instanceof LongTag) {
|
||||
LongTag longTag = (LongTag) tag;
|
||||
return new com.nukkitx.nbt.tag.LongTag(longTag.getName(), longTag.getValue());
|
||||
}
|
||||
|
||||
if (tag instanceof ShortTag) {
|
||||
ShortTag shortTag = (ShortTag) tag;
|
||||
return new com.nukkitx.nbt.tag.ShortTag(shortTag.getName(), shortTag.getValue());
|
||||
}
|
||||
|
||||
if (tag instanceof StringTag) {
|
||||
StringTag stringTag = (StringTag) tag;
|
||||
return new com.nukkitx.nbt.tag.StringTag(stringTag.getName(), stringTag.getValue());
|
||||
}
|
||||
|
||||
if (tag instanceof ListTag) {
|
||||
ListTag listTag = (ListTag) tag;
|
||||
|
||||
List<Tag> tagList = new ArrayList<>();
|
||||
for (com.github.steveice10.opennbt.tag.builtin.Tag value : listTag) {
|
||||
tagList.add(translateToBedrockNBT(value));
|
||||
}
|
||||
Class clazz = CompoundTag.class;
|
||||
if (!tagList.isEmpty()) {
|
||||
clazz = tagList.get(0).getClass();
|
||||
}
|
||||
return new com.nukkitx.nbt.tag.ListTag(listTag.getName(), clazz, tagList);
|
||||
}
|
||||
|
||||
if (tag instanceof com.github.steveice10.opennbt.tag.builtin.CompoundTag) {
|
||||
com.github.steveice10.opennbt.tag.builtin.CompoundTag compoundTag = (com.github.steveice10.opennbt.tag.builtin.CompoundTag) tag;
|
||||
|
||||
return translateNbtToBedrock(compoundTag);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public com.github.steveice10.opennbt.tag.builtin.CompoundTag translateToJavaNBT(com.nukkitx.nbt.tag.CompoundTag tag) {
|
||||
com.github.steveice10.opennbt.tag.builtin.CompoundTag javaTag = new com.github.steveice10.opennbt.tag.builtin.CompoundTag(tag.getName());
|
||||
Map<String, com.github.steveice10.opennbt.tag.builtin.Tag> javaValue = javaTag.getValue();
|
||||
if (tag.getValue() != null && !tag.getValue().isEmpty()) {
|
||||
for (String str : tag.getValue().keySet()) {
|
||||
com.nukkitx.nbt.tag.Tag bedrockTag = tag.get(str);
|
||||
com.github.steveice10.opennbt.tag.builtin.Tag translatedTag = translateToJavaNBT(bedrockTag);
|
||||
if (translatedTag == null)
|
||||
continue;
|
||||
|
||||
javaValue.put(translatedTag.getName(), translatedTag);
|
||||
}
|
||||
}
|
||||
|
||||
javaTag.setValue(javaValue);
|
||||
return javaTag;
|
||||
}
|
||||
|
||||
private com.github.steveice10.opennbt.tag.builtin.Tag translateToJavaNBT(com.nukkitx.nbt.tag.Tag tag) {
|
||||
if (tag instanceof com.nukkitx.nbt.tag.ByteArrayTag) {
|
||||
com.nukkitx.nbt.tag.ByteArrayTag byteArrayTag = (com.nukkitx.nbt.tag.ByteArrayTag) tag;
|
||||
return new ByteArrayTag(byteArrayTag.getName(), byteArrayTag.getValue());
|
||||
}
|
||||
|
||||
if (tag instanceof com.nukkitx.nbt.tag.ByteTag) {
|
||||
com.nukkitx.nbt.tag.ByteTag byteTag = (com.nukkitx.nbt.tag.ByteTag) tag;
|
||||
return new ByteTag(byteTag.getName(), byteTag.getValue());
|
||||
}
|
||||
|
||||
if (tag instanceof com.nukkitx.nbt.tag.DoubleTag) {
|
||||
com.nukkitx.nbt.tag.DoubleTag doubleTag = (com.nukkitx.nbt.tag.DoubleTag) tag;
|
||||
return new DoubleTag(doubleTag.getName(), doubleTag.getValue());
|
||||
}
|
||||
|
||||
if (tag instanceof com.nukkitx.nbt.tag.FloatTag) {
|
||||
com.nukkitx.nbt.tag.FloatTag floatTag = (com.nukkitx.nbt.tag.FloatTag) tag;
|
||||
return new FloatTag(floatTag.getName(), floatTag.getValue());
|
||||
}
|
||||
|
||||
if (tag instanceof com.nukkitx.nbt.tag.IntArrayTag) {
|
||||
com.nukkitx.nbt.tag.IntArrayTag intArrayTag = (com.nukkitx.nbt.tag.IntArrayTag) tag;
|
||||
return new IntArrayTag(intArrayTag.getName(), intArrayTag.getValue());
|
||||
}
|
||||
|
||||
if (tag instanceof com.nukkitx.nbt.tag.IntTag) {
|
||||
com.nukkitx.nbt.tag.IntTag intTag = (com.nukkitx.nbt.tag.IntTag) tag;
|
||||
return new IntTag(intTag.getName(), intTag.getValue());
|
||||
}
|
||||
|
||||
if (tag instanceof com.nukkitx.nbt.tag.LongArrayTag) {
|
||||
com.nukkitx.nbt.tag.LongArrayTag longArrayTag = (com.nukkitx.nbt.tag.LongArrayTag) tag;
|
||||
return new LongArrayTag(longArrayTag.getName(), longArrayTag.getValue());
|
||||
}
|
||||
|
||||
if (tag instanceof com.nukkitx.nbt.tag.LongTag) {
|
||||
com.nukkitx.nbt.tag.LongTag longTag = (com.nukkitx.nbt.tag.LongTag) tag;
|
||||
return new LongTag(longTag.getName(), longTag.getValue());
|
||||
}
|
||||
|
||||
if (tag instanceof com.nukkitx.nbt.tag.ShortTag) {
|
||||
com.nukkitx.nbt.tag.ShortTag shortTag = (com.nukkitx.nbt.tag.ShortTag) tag;
|
||||
return new ShortTag(shortTag.getName(), shortTag.getValue());
|
||||
}
|
||||
|
||||
if (tag instanceof com.nukkitx.nbt.tag.StringTag) {
|
||||
com.nukkitx.nbt.tag.StringTag stringTag = (com.nukkitx.nbt.tag.StringTag) tag;
|
||||
return new StringTag(stringTag.getName(), stringTag.getValue());
|
||||
}
|
||||
|
||||
if (tag instanceof com.nukkitx.nbt.tag.ListTag) {
|
||||
com.nukkitx.nbt.tag.ListTag listTag = (com.nukkitx.nbt.tag.ListTag) tag;
|
||||
|
||||
List<com.github.steveice10.opennbt.tag.builtin.Tag> tags = new ArrayList<>();
|
||||
|
||||
for (Object value : listTag.getValue()) {
|
||||
if (!(value instanceof com.nukkitx.nbt.tag.Tag))
|
||||
continue;
|
||||
|
||||
com.nukkitx.nbt.tag.Tag tagValue = (com.nukkitx.nbt.tag.Tag) value;
|
||||
com.github.steveice10.opennbt.tag.builtin.Tag javaTag = translateToJavaNBT(tagValue);
|
||||
if (javaTag != null)
|
||||
tags.add(javaTag);
|
||||
}
|
||||
return new ListTag(listTag.getName(), tags);
|
||||
}
|
||||
|
||||
if (tag instanceof com.nukkitx.nbt.tag.CompoundTag) {
|
||||
com.nukkitx.nbt.tag.CompoundTag compoundTag = (com.nukkitx.nbt.tag.CompoundTag) tag;
|
||||
return translateToJavaNBT(compoundTag);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
}
|
|
@ -0,0 +1,104 @@
|
|||
/*
|
||||
* Copyright (c) 2019-2020 GeyserMC. http://geysermc.org
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*
|
||||
* @author GeyserMC
|
||||
* @link https://github.com/GeyserMC/Geyser
|
||||
*/
|
||||
|
||||
package org.geysermc.connector.network.translators;
|
||||
|
||||
import com.github.steveice10.mc.protocol.packet.ingame.server.ServerKeepAlivePacket;
|
||||
import com.github.steveice10.mc.protocol.packet.ingame.server.world.ServerUpdateLightPacket;
|
||||
import com.github.steveice10.packetlib.packet.Packet;
|
||||
import com.nukkitx.protocol.bedrock.BedrockPacket;
|
||||
import it.unimi.dsi.fastutil.objects.ObjectArrayList;
|
||||
import org.geysermc.connector.GeyserConnector;
|
||||
import org.geysermc.connector.network.session.GeyserSession;
|
||||
import org.reflections.Reflections;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
public class PacketTranslatorRegistry<T> {
|
||||
private final Map<Class<? extends T>, PacketTranslator<? extends T>> translators = new HashMap<>();
|
||||
|
||||
public static final PacketTranslatorRegistry<Packet> JAVA_TRANSLATOR = new PacketTranslatorRegistry<>();
|
||||
public static final PacketTranslatorRegistry<BedrockPacket> BEDROCK_TRANSLATOR = new PacketTranslatorRegistry<>();
|
||||
|
||||
private static final ObjectArrayList<Class<?>> IGNORED_PACKETS = new ObjectArrayList<>();
|
||||
|
||||
static {
|
||||
Reflections ref = new Reflections("org.geysermc.connector.network.translators");
|
||||
|
||||
for (Class<?> clazz : ref.getTypesAnnotatedWith(Translator.class)) {
|
||||
Class<?> packet = clazz.getAnnotation(Translator.class).packet();
|
||||
|
||||
GeyserConnector.getInstance().getLogger().debug("Found annotated translator: " + clazz.getCanonicalName() + " : " + packet.getSimpleName());
|
||||
|
||||
try {
|
||||
if (Packet.class.isAssignableFrom(packet)) {
|
||||
Class<? extends Packet> targetPacket = (Class<? extends Packet>) packet;
|
||||
PacketTranslator<? extends Packet> translator = (PacketTranslator<? extends Packet>) clazz.newInstance();
|
||||
|
||||
JAVA_TRANSLATOR.translators.put(targetPacket, translator);
|
||||
} else if (BedrockPacket.class.isAssignableFrom(packet)) {
|
||||
Class<? extends BedrockPacket> targetPacket = (Class<? extends BedrockPacket>) packet;
|
||||
PacketTranslator<? extends BedrockPacket> translator = (PacketTranslator<? extends BedrockPacket>) clazz.newInstance();
|
||||
|
||||
BEDROCK_TRANSLATOR.translators.put(targetPacket, translator);
|
||||
} else {
|
||||
GeyserConnector.getInstance().getLogger().error("Class " + clazz.getCanonicalName() + " is annotated as a translator but has an invalid target packet.");
|
||||
}
|
||||
} catch (InstantiationException | IllegalAccessException e) {
|
||||
GeyserConnector.getInstance().getLogger().error("Could not instantiate annotated translator " + clazz.getCanonicalName() + ".");
|
||||
}
|
||||
}
|
||||
|
||||
IGNORED_PACKETS.add(ServerKeepAlivePacket.class); // Handled by MCProtocolLib
|
||||
IGNORED_PACKETS.add(ServerUpdateLightPacket.class); // Light is handled on Bedrock for us
|
||||
}
|
||||
|
||||
private PacketTranslatorRegistry() {
|
||||
}
|
||||
|
||||
public static void init() {
|
||||
// no-op
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public <P extends T> boolean translate(Class<? extends P> clazz, P packet, GeyserSession session) {
|
||||
if (!session.getUpstream().isClosed() && !session.isClosed()) {
|
||||
try {
|
||||
if (translators.containsKey(clazz)) {
|
||||
((PacketTranslator<P>) translators.get(clazz)).translate(packet, session);
|
||||
return true;
|
||||
} else {
|
||||
if (!IGNORED_PACKETS.contains(clazz))
|
||||
GeyserConnector.getInstance().getLogger().debug("Could not find packet for " + (packet.toString().length() > 25 ? packet.getClass().getSimpleName() : packet));
|
||||
}
|
||||
} catch (Throwable ex) {
|
||||
GeyserConnector.getInstance().getLogger().error("Could not translate packet " + packet.getClass().getSimpleName(), ex);
|
||||
ex.printStackTrace();
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
|
@ -1,68 +0,0 @@
|
|||
/*
|
||||
* Copyright (c) 2019-2020 GeyserMC. http://geysermc.org
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*
|
||||
* @author GeyserMC
|
||||
* @link https://github.com/GeyserMC/Geyser
|
||||
*/
|
||||
|
||||
package org.geysermc.connector.network.translators;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import org.geysermc.connector.GeyserConnector;
|
||||
import org.geysermc.connector.network.session.GeyserSession;
|
||||
|
||||
import com.github.steveice10.packetlib.packet.Packet;
|
||||
import com.nukkitx.protocol.bedrock.BedrockPacket;
|
||||
|
||||
public class Registry<T> {
|
||||
private final Map<Class<? extends T>, PacketTranslator<? extends T>> MAP = new HashMap<>();
|
||||
|
||||
public static final Registry<Packet> JAVA = new Registry<>();
|
||||
public static final Registry<BedrockPacket> BEDROCK = new Registry<>();
|
||||
|
||||
public static void registerJava(Class<? extends Packet> targetPacket, PacketTranslator<? extends Packet> translator) {
|
||||
JAVA.MAP.put(targetPacket, translator);
|
||||
}
|
||||
|
||||
public static void registerBedrock(Class<? extends BedrockPacket> targetPacket, PacketTranslator<? extends BedrockPacket> translator) {
|
||||
BEDROCK.MAP.put(targetPacket, translator);
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public <P extends T> boolean translate(Class<? extends P> clazz, P packet, GeyserSession session) {
|
||||
if (!session.getUpstream().isClosed() && !session.isClosed()) {
|
||||
try {
|
||||
if (MAP.containsKey(clazz)) {
|
||||
((PacketTranslator<P>) MAP.get(clazz)).translate(packet, session);
|
||||
return true;
|
||||
} else {
|
||||
GeyserConnector.getInstance().getLogger().debug("Could not find packet for " + (packet.toString().length() > 25 ? packet.getClass().getSimpleName() : packet));
|
||||
}
|
||||
} catch (Throwable ex) {
|
||||
GeyserConnector.getInstance().getLogger().error("Could not translate packet " + packet.getClass().getSimpleName(), ex);
|
||||
ex.printStackTrace();
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
|
@ -1,176 +0,0 @@
|
|||
/*
|
||||
* Copyright (c) 2019-2020 GeyserMC. http://geysermc.org
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*
|
||||
* @author GeyserMC
|
||||
* @link https://github.com/GeyserMC/Geyser
|
||||
*/
|
||||
|
||||
package org.geysermc.connector.network.translators;
|
||||
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import com.github.steveice10.mc.protocol.data.game.window.WindowType;
|
||||
import com.nukkitx.protocol.bedrock.data.ContainerType;
|
||||
import it.unimi.dsi.fastutil.objects.ObjectArrayList;
|
||||
import org.geysermc.connector.GeyserConnector;
|
||||
import org.geysermc.connector.network.translators.world.block.BlockTranslator;
|
||||
import org.geysermc.connector.network.translators.world.block.entity.*;
|
||||
import org.geysermc.connector.network.translators.inventory.*;
|
||||
import org.geysermc.connector.network.translators.inventory.updater.ContainerInventoryUpdater;
|
||||
import org.geysermc.connector.network.translators.inventory.updater.InventoryUpdater;
|
||||
import org.geysermc.connector.network.translators.item.ItemTranslator;
|
||||
import org.reflections.Reflections;
|
||||
|
||||
import com.github.steveice10.packetlib.packet.Packet;
|
||||
import com.nukkitx.nbt.CompoundTagBuilder;
|
||||
import com.nukkitx.nbt.NbtUtils;
|
||||
import com.nukkitx.nbt.stream.NBTOutputStream;
|
||||
import com.nukkitx.nbt.tag.CompoundTag;
|
||||
import com.nukkitx.protocol.bedrock.BedrockPacket;
|
||||
|
||||
import lombok.Getter;
|
||||
|
||||
public class Translators {
|
||||
|
||||
@Getter
|
||||
private static ItemTranslator itemTranslator;
|
||||
|
||||
@Getter
|
||||
private static Map<WindowType, InventoryTranslator> inventoryTranslators = new HashMap<>();
|
||||
|
||||
@Getter
|
||||
private static Map<String, BlockEntityTranslator> blockEntityTranslators = new HashMap<>();
|
||||
|
||||
@Getter
|
||||
private static ObjectArrayList<RequiresBlockState> requiresBlockStateMap = new ObjectArrayList<>();
|
||||
|
||||
private static final CompoundTag EMPTY_TAG = CompoundTagBuilder.builder().buildRootTag();
|
||||
public static final byte[] EMPTY_LEVEL_CHUNK_DATA;
|
||||
|
||||
static {
|
||||
try (ByteArrayOutputStream outputStream = new ByteArrayOutputStream()) {
|
||||
outputStream.write(new byte[258]); // Biomes + Border Size + Extra Data Size
|
||||
|
||||
try (NBTOutputStream stream = NbtUtils.createNetworkWriter(outputStream)) {
|
||||
stream.write(EMPTY_TAG);
|
||||
}
|
||||
|
||||
EMPTY_LEVEL_CHUNK_DATA = outputStream.toByteArray();
|
||||
}catch (IOException e) {
|
||||
throw new AssertionError("Unable to generate empty level chunk data");
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public static void start() {
|
||||
Reflections ref = new Reflections("org.geysermc.connector.network.translators");
|
||||
|
||||
for (Class<?> clazz : ref.getTypesAnnotatedWith(Translator.class)) {
|
||||
Class<?> packet = clazz.getAnnotation(Translator.class).packet();
|
||||
|
||||
GeyserConnector.getInstance().getLogger().debug("Found annotated translator: " + clazz.getCanonicalName() + " : " + packet.getSimpleName());
|
||||
|
||||
try {
|
||||
if (Packet.class.isAssignableFrom(packet)) {
|
||||
Class<? extends Packet> targetPacket = (Class<? extends Packet>) packet;
|
||||
PacketTranslator<? extends Packet> translator = (PacketTranslator<? extends Packet>) clazz.newInstance();
|
||||
|
||||
Registry.registerJava(targetPacket, translator);
|
||||
|
||||
} else if (BedrockPacket.class.isAssignableFrom(packet)) {
|
||||
Class<? extends BedrockPacket> targetPacket = (Class<? extends BedrockPacket>) packet;
|
||||
PacketTranslator<? extends BedrockPacket> translator = (PacketTranslator<? extends BedrockPacket>) clazz.newInstance();
|
||||
|
||||
Registry.registerBedrock(targetPacket, translator);
|
||||
|
||||
} else {
|
||||
GeyserConnector.getInstance().getLogger().error("Class " + clazz.getCanonicalName() + " is annotated as a translator but has an invalid target packet.");
|
||||
}
|
||||
} catch (InstantiationException | IllegalAccessException e) {
|
||||
GeyserConnector.getInstance().getLogger().error("Could not instantiate annotated translator " + clazz.getCanonicalName() + ".");
|
||||
}
|
||||
}
|
||||
|
||||
itemTranslator = new ItemTranslator();
|
||||
itemTranslator.init();
|
||||
BlockTranslator.init();
|
||||
|
||||
registerBlockEntityTranslators();
|
||||
registerInventoryTranslators();
|
||||
}
|
||||
|
||||
private static void registerBlockEntityTranslators() {
|
||||
Reflections ref = new Reflections("org.geysermc.connector.network.translators.world.block.entity");
|
||||
|
||||
for (Class<?> clazz : ref.getTypesAnnotatedWith(BlockEntity.class)) {
|
||||
|
||||
GeyserConnector.getInstance().getLogger().debug("Found annotated block entity: " + clazz.getCanonicalName());
|
||||
|
||||
try {
|
||||
blockEntityTranslators.put(clazz.getAnnotation(BlockEntity.class).name(), (BlockEntityTranslator) clazz.newInstance());
|
||||
} catch (InstantiationException | IllegalAccessException e) {
|
||||
GeyserConnector.getInstance().getLogger().error("Could not instantiate annotated block entity " + clazz.getCanonicalName() + ".");
|
||||
}
|
||||
}
|
||||
|
||||
for (Class<?> clazz : ref.getSubTypesOf(RequiresBlockState.class)) {
|
||||
|
||||
GeyserConnector.getInstance().getLogger().debug("Found block entity that requires block state: " + clazz.getCanonicalName());
|
||||
|
||||
try {
|
||||
requiresBlockStateMap.add((RequiresBlockState) clazz.newInstance());
|
||||
} catch (InstantiationException | IllegalAccessException e) {
|
||||
GeyserConnector.getInstance().getLogger().error("Could not instantiate required block state " + clazz.getCanonicalName() + ".");
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
private static void registerInventoryTranslators() {
|
||||
inventoryTranslators.put(null, new PlayerInventoryTranslator()); //player inventory
|
||||
inventoryTranslators.put(WindowType.GENERIC_9X1, new SingleChestInventoryTranslator(9));
|
||||
inventoryTranslators.put(WindowType.GENERIC_9X2, new SingleChestInventoryTranslator(18));
|
||||
inventoryTranslators.put(WindowType.GENERIC_9X3, new SingleChestInventoryTranslator(27));
|
||||
inventoryTranslators.put(WindowType.GENERIC_9X4, new DoubleChestInventoryTranslator(36));
|
||||
inventoryTranslators.put(WindowType.GENERIC_9X5, new DoubleChestInventoryTranslator(45));
|
||||
inventoryTranslators.put(WindowType.GENERIC_9X6, new DoubleChestInventoryTranslator(54));
|
||||
inventoryTranslators.put(WindowType.BREWING_STAND, new BrewingInventoryTranslator());
|
||||
inventoryTranslators.put(WindowType.ANVIL, new AnvilInventoryTranslator());
|
||||
inventoryTranslators.put(WindowType.CRAFTING, new CraftingInventoryTranslator());
|
||||
inventoryTranslators.put(WindowType.GRINDSTONE, new GrindstoneInventoryTranslator());
|
||||
inventoryTranslators.put(WindowType.MERCHANT, new MerchantInventoryTranslator());
|
||||
//inventoryTranslators.put(WindowType.ENCHANTMENT, new EnchantmentInventoryTranslator()); //TODO
|
||||
|
||||
InventoryTranslator furnace = new FurnaceInventoryTranslator();
|
||||
inventoryTranslators.put(WindowType.FURNACE, furnace);
|
||||
inventoryTranslators.put(WindowType.BLAST_FURNACE, furnace);
|
||||
inventoryTranslators.put(WindowType.SMOKER, furnace);
|
||||
|
||||
InventoryUpdater containerUpdater = new ContainerInventoryUpdater();
|
||||
inventoryTranslators.put(WindowType.GENERIC_3X3, new BlockInventoryTranslator(9, "minecraft:dispenser[facing=north,triggered=false]", ContainerType.DISPENSER, containerUpdater));
|
||||
inventoryTranslators.put(WindowType.HOPPER, new BlockInventoryTranslator(5, "minecraft:hopper[enabled=false,facing=down]", ContainerType.HOPPER, containerUpdater));
|
||||
inventoryTranslators.put(WindowType.SHULKER_BOX, new BlockInventoryTranslator(27, "minecraft:shulker_box[facing=north]", ContainerType.CONTAINER, containerUpdater));
|
||||
//inventoryTranslators.put(WindowType.BEACON, new BlockInventoryTranslator(1, "minecraft:beacon", ContainerType.BEACON)); //TODO
|
||||
}
|
||||
}
|
|
@ -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.connector.network.translators.bedrock;
|
||||
|
||||
import com.github.steveice10.mc.protocol.data.game.entity.player.GameMode;
|
||||
import com.github.steveice10.mc.protocol.packet.ingame.client.player.ClientPlayerAbilitiesPacket;
|
||||
import com.nukkitx.protocol.bedrock.packet.AdventureSettingsPacket;
|
||||
import org.geysermc.connector.network.session.GeyserSession;
|
||||
import org.geysermc.connector.network.translators.PacketTranslator;
|
||||
import org.geysermc.connector.network.translators.Translator;
|
||||
|
||||
@Translator(packet = AdventureSettingsPacket.class)
|
||||
public class BedrockAdventureSettingsTranslator extends PacketTranslator<AdventureSettingsPacket> {
|
||||
|
||||
@Override
|
||||
public void translate(AdventureSettingsPacket packet, GeyserSession session) {
|
||||
// Only canFly and flying are used by the server
|
||||
// https://wiki.vg/Protocol#Player_Abilities_.28serverbound.29
|
||||
boolean canFly = packet.getFlags().contains(AdventureSettingsPacket.Flag.MAY_FLY);
|
||||
boolean flying = packet.getFlags().contains(AdventureSettingsPacket.Flag.FLYING);
|
||||
boolean creative = session.getGameMode() == GameMode.CREATIVE;
|
||||
ClientPlayerAbilitiesPacket abilitiesPacket = new ClientPlayerAbilitiesPacket(
|
||||
false, canFly, flying, creative, 0.05f, 0.1f
|
||||
);
|
||||
session.sendDownstreamPacket(abilitiesPacket);
|
||||
}
|
||||
}
|
|
@ -31,6 +31,7 @@ import org.geysermc.connector.network.translators.Translator;
|
|||
|
||||
import com.github.steveice10.mc.protocol.data.game.entity.player.Hand;
|
||||
import com.github.steveice10.mc.protocol.packet.ingame.client.player.ClientPlayerSwingArmPacket;
|
||||
import com.github.steveice10.mc.protocol.packet.ingame.client.world.ClientSteerBoatPacket;
|
||||
import com.nukkitx.protocol.bedrock.packet.AnimatePacket;
|
||||
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
@ -38,6 +39,9 @@ import java.util.concurrent.TimeUnit;
|
|||
@Translator(packet = AnimatePacket.class)
|
||||
public class BedrockAnimateTranslator extends PacketTranslator<AnimatePacket> {
|
||||
|
||||
private boolean isSteeringLeft;
|
||||
private boolean isSteeringRight;
|
||||
|
||||
@Override
|
||||
public void translate(AnimatePacket packet, GeyserSession session) {
|
||||
// Stop the player sending animations before they have fully spawned into the server
|
||||
|
@ -54,6 +58,18 @@ public class BedrockAnimateTranslator extends PacketTranslator<AnimatePacket> {
|
|||
TimeUnit.MILLISECONDS
|
||||
);
|
||||
break;
|
||||
// These two might need to be flipped, but my recommendation is getting moving working first
|
||||
case ROW_LEFT:
|
||||
// Packet value is a float of how long one has been rowing, so we convert that into a boolean
|
||||
isSteeringLeft = packet.getRowingTime() > 0.0;
|
||||
ClientSteerBoatPacket steerLeftPacket = new ClientSteerBoatPacket(isSteeringRight, isSteeringLeft);
|
||||
session.sendDownstreamPacket(steerLeftPacket);
|
||||
break;
|
||||
case ROW_RIGHT:
|
||||
isSteeringRight = packet.getRowingTime() > 0.0;
|
||||
ClientSteerBoatPacket steerRightPacket = new ClientSteerBoatPacket(isSteeringRight, isSteeringLeft);
|
||||
session.sendDownstreamPacket(steerRightPacket);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -31,15 +31,13 @@ import com.github.steveice10.mc.protocol.packet.ingame.client.window.ClientMoveI
|
|||
import com.nukkitx.math.vector.Vector3i;
|
||||
import com.nukkitx.protocol.bedrock.packet.BlockPickRequestPacket;
|
||||
import com.nukkitx.protocol.bedrock.packet.PlayerHotbarPacket;
|
||||
import org.geysermc.connector.entity.Entity;
|
||||
import org.geysermc.connector.inventory.Inventory;
|
||||
import org.geysermc.connector.network.session.GeyserSession;
|
||||
import org.geysermc.connector.network.translators.PacketTranslator;
|
||||
import org.geysermc.connector.network.translators.Translator;
|
||||
import org.geysermc.connector.network.translators.item.ItemEntry;
|
||||
import org.geysermc.connector.network.translators.item.ItemRegistry;
|
||||
import org.geysermc.connector.network.translators.world.block.BlockTranslator;
|
||||
import org.geysermc.connector.network.translators.item.ItemTranslator;
|
||||
import org.geysermc.connector.network.translators.Translators;
|
||||
|
||||
@Translator(packet = BlockPickRequestPacket.class)
|
||||
public class BedrockBlockPickRequestPacketTranslator extends PacketTranslator<BlockPickRequestPacket> {
|
||||
|
@ -61,14 +59,13 @@ public class BedrockBlockPickRequestPacketTranslator extends PacketTranslator<Bl
|
|||
}
|
||||
|
||||
String targetIdentifier = BlockTranslator.getJavaIdBlockMap().inverse().get(blockToPick).split("\\[")[0];
|
||||
ItemTranslator itemTranslator = Translators.getItemTranslator();
|
||||
|
||||
// Check hotbar for item
|
||||
for (int i = 36; i < 45; i++) {
|
||||
if (inventory.getItem(i) == null) {
|
||||
continue;
|
||||
}
|
||||
ItemEntry item = itemTranslator.getItem(inventory.getItem(i));
|
||||
ItemEntry item = ItemRegistry.getItem(inventory.getItem(i));
|
||||
// If this isn't the item we're looking for
|
||||
if (!item.getJavaIdentifier().equals(targetIdentifier)) {
|
||||
continue;
|
||||
|
@ -90,7 +87,7 @@ public class BedrockBlockPickRequestPacketTranslator extends PacketTranslator<Bl
|
|||
if (inventory.getItem(i) == null) {
|
||||
continue;
|
||||
}
|
||||
ItemEntry item = itemTranslator.getItem(inventory.getItem(i));
|
||||
ItemEntry item = ItemRegistry.getItem(inventory.getItem(i));
|
||||
// If this isn't the item we're looking for
|
||||
if (!item.getJavaIdentifier().equals(targetIdentifier)) {
|
||||
continue;
|
||||
|
|
|
@ -38,17 +38,21 @@ public class BedrockContainerCloseTranslator extends PacketTranslator<ContainerC
|
|||
|
||||
@Override
|
||||
public void translate(ContainerClosePacket packet, GeyserSession session) {
|
||||
session.setLastWindowCloseTime(0);
|
||||
byte windowId = packet.getWindowId();
|
||||
if (windowId == -1) { //player inventory or crafting table
|
||||
Inventory openInventory = session.getInventoryCache().getOpenInventory();
|
||||
if (windowId == -1) { //player inventory or crafting table
|
||||
if (openInventory != null) {
|
||||
windowId = (byte) openInventory.getId();
|
||||
} else {
|
||||
windowId = 0;
|
||||
}
|
||||
}
|
||||
|
||||
if (windowId == 0 || (openInventory != null && openInventory.getId() == windowId)) {
|
||||
ClientCloseWindowPacket closeWindowPacket = new ClientCloseWindowPacket(windowId);
|
||||
session.sendDownstreamPacket(closeWindowPacket);
|
||||
session.getDownstream().getSession().send(closeWindowPacket);
|
||||
InventoryUtils.closeInventory(session, windowId);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -25,6 +25,8 @@
|
|||
|
||||
package org.geysermc.connector.network.translators.bedrock;
|
||||
|
||||
import com.nukkitx.protocol.bedrock.data.EntityData;
|
||||
import com.nukkitx.protocol.bedrock.data.EntityFlag;
|
||||
import org.geysermc.connector.entity.Entity;
|
||||
import org.geysermc.connector.network.session.GeyserSession;
|
||||
import org.geysermc.connector.network.translators.PacketTranslator;
|
||||
|
@ -32,9 +34,11 @@ import org.geysermc.connector.network.translators.Translator;
|
|||
|
||||
import com.github.steveice10.mc.protocol.data.game.entity.player.Hand;
|
||||
import com.github.steveice10.mc.protocol.data.game.entity.player.InteractAction;
|
||||
import com.github.steveice10.mc.protocol.data.game.entity.player.PlayerState;
|
||||
import com.github.steveice10.mc.protocol.packet.ingame.client.player.ClientPlayerInteractEntityPacket;
|
||||
import com.github.steveice10.mc.protocol.packet.ingame.client.player.ClientPlayerStatePacket;
|
||||
import com.nukkitx.protocol.bedrock.packet.InteractPacket;
|
||||
import org.geysermc.connector.network.translators.item.ItemTranslator;
|
||||
import org.geysermc.connector.network.translators.item.ItemRegistry;
|
||||
|
||||
@Translator(packet = InteractPacket.class)
|
||||
public class BedrockInteractTranslator extends PacketTranslator<InteractPacket> {
|
||||
|
@ -47,7 +51,7 @@ public class BedrockInteractTranslator extends PacketTranslator<InteractPacket>
|
|||
|
||||
switch (packet.getAction()) {
|
||||
case INTERACT:
|
||||
if (session.getInventory().getItem(session.getInventory().getHeldItemSlot() + 36).getId() == ItemTranslator.SHIELD) {
|
||||
if (session.getInventory().getItem(session.getInventory().getHeldItemSlot() + 36).getId() == ItemRegistry.SHIELD) {
|
||||
break;
|
||||
}
|
||||
ClientPlayerInteractEntityPacket interactPacket = new ClientPlayerInteractEntityPacket((int) entity.getEntityId(),
|
||||
|
@ -59,6 +63,58 @@ public class BedrockInteractTranslator extends PacketTranslator<InteractPacket>
|
|||
InteractAction.ATTACK, Hand.MAIN_HAND);
|
||||
session.sendDownstreamPacket(attackPacket);
|
||||
break;
|
||||
case LEAVE_VEHICLE:
|
||||
ClientPlayerStatePacket sneakPacket = new ClientPlayerStatePacket((int) entity.getEntityId(), PlayerState.START_SNEAKING);
|
||||
session.sendDownstreamPacket(sneakPacket);
|
||||
session.setRidingVehicleEntity(null);
|
||||
break;
|
||||
case MOUSEOVER:
|
||||
// Handle the buttons for mobile - "Mount", etc; and the suggestions for console - "ZL: Mount", etc
|
||||
if (packet.getRuntimeEntityId() != 0) {
|
||||
Entity interactEntity = session.getEntityCache().getEntityByGeyserId(packet.getRuntimeEntityId());
|
||||
if (interactEntity == null)
|
||||
return;
|
||||
|
||||
String interactiveTag;
|
||||
switch (interactEntity.getEntityType()) {
|
||||
case PIG:
|
||||
if (interactEntity.getMetadata().getFlags().getFlag(EntityFlag.SADDLED)) {
|
||||
interactiveTag = "action.interact.mount";
|
||||
} else interactiveTag = "";
|
||||
break;
|
||||
case HORSE:
|
||||
case SKELETON_HORSE:
|
||||
case ZOMBIE_HORSE:
|
||||
case DONKEY:
|
||||
case MULE:
|
||||
case LLAMA:
|
||||
case TRADER_LLAMA:
|
||||
if (interactEntity.getMetadata().getFlags().getFlag(EntityFlag.TAMED)) {
|
||||
interactiveTag = "action.interact.ride.horse";
|
||||
} else {
|
||||
interactiveTag = "action.interact.mount";
|
||||
}
|
||||
break;
|
||||
case BOAT:
|
||||
interactiveTag = "action.interact.ride.boat";
|
||||
break;
|
||||
case MINECART:
|
||||
interactiveTag = "action.interact.ride.minecart";
|
||||
break;
|
||||
default:
|
||||
return; // No need to process any further since there is no interactive tag
|
||||
}
|
||||
session.getPlayerEntity().getMetadata().put(EntityData.INTERACTIVE_TAG, interactiveTag);
|
||||
session.getPlayerEntity().updateBedrockMetadata(session);
|
||||
} else {
|
||||
if (!(session.getPlayerEntity().getMetadata().get(EntityData.INTERACTIVE_TAG) == null) ||
|
||||
!(session.getPlayerEntity().getMetadata().get(EntityData.INTERACTIVE_TAG) == "")) {
|
||||
// No interactive tag should be sent
|
||||
session.getPlayerEntity().getMetadata().remove(EntityData.INTERACTIVE_TAG);
|
||||
session.getPlayerEntity().updateBedrockMetadata(session);
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -25,6 +25,7 @@
|
|||
|
||||
package org.geysermc.connector.network.translators.bedrock;
|
||||
|
||||
import com.github.steveice10.mc.protocol.data.game.entity.metadata.ItemStack;
|
||||
import com.github.steveice10.mc.protocol.data.game.entity.metadata.Position;
|
||||
import com.github.steveice10.mc.protocol.data.game.entity.player.GameMode;
|
||||
import com.github.steveice10.mc.protocol.data.game.entity.player.Hand;
|
||||
|
@ -44,14 +45,13 @@ import com.nukkitx.protocol.bedrock.packet.InventoryTransactionPacket;
|
|||
|
||||
import org.geysermc.connector.entity.Entity;
|
||||
import org.geysermc.connector.entity.ItemFrameEntity;
|
||||
import org.geysermc.connector.entity.living.merchant.VillagerEntity;
|
||||
import org.geysermc.connector.inventory.Inventory;
|
||||
import org.geysermc.connector.network.session.GeyserSession;
|
||||
import org.geysermc.connector.network.translators.PacketTranslator;
|
||||
import org.geysermc.connector.network.translators.Translator;
|
||||
import org.geysermc.connector.network.translators.Translators;
|
||||
import org.geysermc.connector.network.translators.inventory.InventoryTranslator;
|
||||
import org.geysermc.connector.network.translators.item.ItemEntry;
|
||||
import org.geysermc.connector.network.translators.item.ItemTranslator;
|
||||
import org.geysermc.connector.network.translators.item.ItemRegistry;
|
||||
import org.geysermc.connector.network.translators.sound.EntitySoundInteractionHandler;
|
||||
import org.geysermc.connector.network.translators.world.block.BlockTranslator;
|
||||
import org.geysermc.connector.utils.InventoryUtils;
|
||||
|
@ -65,12 +65,12 @@ public class BedrockInventoryTransactionTranslator extends PacketTranslator<Inve
|
|||
case NORMAL:
|
||||
Inventory inventory = session.getInventoryCache().getOpenInventory();
|
||||
if (inventory == null) inventory = session.getInventory();
|
||||
Translators.getInventoryTranslators().get(inventory.getWindowType()).translateActions(session, inventory, packet.getActions());
|
||||
InventoryTranslator.INVENTORY_TRANSLATORS.get(inventory.getWindowType()).translateActions(session, inventory, packet.getActions());
|
||||
break;
|
||||
case INVENTORY_MISMATCH:
|
||||
Inventory inv = session.getInventoryCache().getOpenInventory();
|
||||
if (inv == null) inv = session.getInventory();
|
||||
Translators.getInventoryTranslators().get(inv.getWindowType()).updateInventory(session, inv);
|
||||
InventoryTranslator.INVENTORY_TRANSLATORS.get(inv.getWindowType()).updateInventory(session, inv);
|
||||
InventoryUtils.updateCursor(session);
|
||||
break;
|
||||
case ITEM_USE:
|
||||
|
@ -97,6 +97,13 @@ public class BedrockInventoryTransactionTranslator extends PacketTranslator<Inve
|
|||
packet.getClickPosition().getX(), packet.getClickPosition().getY(), packet.getClickPosition().getZ(),
|
||||
false);
|
||||
session.sendDownstreamPacket(blockPacket);
|
||||
|
||||
// Otherwise boats will not be able to be placed in survival
|
||||
if (packet.getItemInHand() != null && packet.getItemInHand().getId() == ItemRegistry.BOAT) {
|
||||
ClientPlayerUseItemPacket itemPacket = new ClientPlayerUseItemPacket(Hand.MAIN_HAND);
|
||||
session.sendDownstreamPacket(itemPacket);
|
||||
}
|
||||
|
||||
Vector3i blockPos = packet.getBlockPosition();
|
||||
// TODO: Find a better way to do this?
|
||||
switch (packet.getFace()) {
|
||||
|
@ -119,7 +126,7 @@ public class BedrockInventoryTransactionTranslator extends PacketTranslator<Inve
|
|||
blockPos = blockPos.add(1, 0, 0);
|
||||
break;
|
||||
}
|
||||
ItemEntry handItem = Translators.getItemTranslator().getItem(packet.getItemInHand());
|
||||
ItemEntry handItem = ItemRegistry.getItem(packet.getItemInHand());
|
||||
if (handItem.isBlock()) {
|
||||
session.setLastBlockPlacePosition(blockPos);
|
||||
session.setLastBlockPlacedId(handItem.getJavaIdentifier());
|
||||
|
@ -128,11 +135,14 @@ public class BedrockInventoryTransactionTranslator extends PacketTranslator<Inve
|
|||
session.setInteracting(true);
|
||||
break;
|
||||
case 1:
|
||||
if (session.getInventory().getItem(session.getInventory().getHeldItemSlot() + 36).getId() == ItemTranslator.SHIELD) {
|
||||
ItemStack shieldSlot = session.getInventory().getItem(session.getInventory().getHeldItemSlot() + 36);
|
||||
if (shieldSlot != null && shieldSlot.getId() == ItemRegistry.SHIELD) {
|
||||
break;
|
||||
} // Handled in Entity.java
|
||||
ClientPlayerUseItemPacket useItemPacket = new ClientPlayerUseItemPacket(Hand.MAIN_HAND);
|
||||
session.sendDownstreamPacket(useItemPacket);
|
||||
// Used for sleeping in beds
|
||||
session.setLastInteractionPosition(packet.getBlockPosition());
|
||||
break;
|
||||
case 2:
|
||||
BlockState blockState = session.getConnector().getWorldManager().getBlockAt(session, packet.getBlockPosition().getX(), packet.getBlockPosition().getY(), packet.getBlockPosition().getZ());
|
||||
|
|
|
@ -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.network.translators.bedrock;
|
||||
|
||||
import com.github.steveice10.mc.protocol.packet.ingame.client.world.ClientVehicleMovePacket;
|
||||
import com.nukkitx.protocol.bedrock.packet.MoveEntityAbsolutePacket;
|
||||
import org.geysermc.connector.network.session.GeyserSession;
|
||||
import org.geysermc.connector.network.translators.PacketTranslator;
|
||||
import org.geysermc.connector.network.translators.Translator;
|
||||
|
||||
// Used for horses
|
||||
@Translator(packet = MoveEntityAbsolutePacket.class)
|
||||
public class BedrockMoveEntityAbsoluteTranslator extends PacketTranslator<MoveEntityAbsolutePacket> {
|
||||
|
||||
@Override
|
||||
public void translate(MoveEntityAbsolutePacket packet, GeyserSession session) {
|
||||
|
||||
ClientVehicleMovePacket clientVehicleMovePacket = new ClientVehicleMovePacket(
|
||||
packet.getPosition().getX(), packet.getPosition().getY(), packet.getPosition().getZ(),
|
||||
packet.getRotation().getY() - 90, packet.getRotation().getX()
|
||||
);
|
||||
session.sendDownstreamPacket(clientVehicleMovePacket);
|
||||
}
|
||||
}
|
|
@ -85,6 +85,7 @@ public class BedrockMovePlayerTranslator extends PacketTranslator<MovePlayerPack
|
|||
Vector3f rotation = Vector3f.from(packet.getRotation().getY(), packet.getRotation().getX(), packet.getRotation().getY());
|
||||
entity.setPosition(packet.getPosition().sub(0, EntityType.PLAYER.getOffset(), 0));
|
||||
entity.setRotation(rotation);
|
||||
entity.setOnGround(packet.isOnGround());
|
||||
|
||||
/*
|
||||
boolean colliding = false;
|
||||
|
|
|
@ -0,0 +1,21 @@
|
|||
package org.geysermc.connector.network.translators.bedrock;
|
||||
|
||||
import com.github.steveice10.mc.protocol.packet.ingame.client.world.ClientSteerVehiclePacket;
|
||||
import com.nukkitx.protocol.bedrock.packet.PlayerInputPacket;
|
||||
import org.geysermc.connector.network.session.GeyserSession;
|
||||
import org.geysermc.connector.network.translators.PacketTranslator;
|
||||
import org.geysermc.connector.network.translators.Translator;
|
||||
|
||||
// Makes minecarts respond to player input
|
||||
@Translator(packet = PlayerInputPacket.class)
|
||||
public class BedrockPlayerInputTranslator extends PacketTranslator<PlayerInputPacket> {
|
||||
|
||||
@Override
|
||||
public void translate(PlayerInputPacket packet, GeyserSession session) {
|
||||
ClientSteerVehiclePacket clientSteerVehiclePacket = new ClientSteerVehiclePacket(
|
||||
packet.getInputMotion().getX(), packet.getInputMotion().getY(), packet.isJumping(), packet.isSneaking()
|
||||
);
|
||||
|
||||
session.sendDownstreamPacket(clientSteerVehiclePacket);
|
||||
}
|
||||
}
|
|
@ -21,29 +21,30 @@
|
|||
*
|
||||
* @author GeyserMC
|
||||
* @link https://github.com/GeyserMC/Geyser
|
||||
*
|
||||
*/
|
||||
|
||||
package org.geysermc.connector.utils;
|
||||
package org.geysermc.connector.network.translators.effect;
|
||||
|
||||
import com.fasterxml.jackson.databind.JsonNode;
|
||||
import com.github.steveice10.mc.protocol.data.game.world.particle.ParticleType;
|
||||
import com.nukkitx.protocol.bedrock.data.LevelEventType;
|
||||
import com.nukkitx.protocol.bedrock.data.SoundEvent;
|
||||
|
||||
import it.unimi.dsi.fastutil.ints.Int2ObjectMap;
|
||||
import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap;
|
||||
|
||||
import lombok.NonNull;
|
||||
|
||||
import org.geysermc.connector.GeyserConnector;
|
||||
import org.geysermc.connector.network.translators.effect.Effect;
|
||||
import org.geysermc.connector.utils.FileUtils;
|
||||
|
||||
import java.io.InputStream;
|
||||
import java.util.HashMap;
|
||||
import java.util.Iterator;
|
||||
import java.util.Map;
|
||||
|
||||
public class EffectUtils {
|
||||
/**
|
||||
* Registry for particles and effects.
|
||||
*/
|
||||
public class EffectRegistry {
|
||||
|
||||
public static final Map<String, Effect> EFFECTS = new HashMap<>();
|
||||
public static final Int2ObjectMap<SoundEvent> RECORDS = new Int2ObjectOpenHashMap<>();
|
||||
|
@ -57,10 +58,10 @@ public class EffectUtils {
|
|||
|
||||
static {
|
||||
/* Load particles */
|
||||
InputStream particleStream = Toolbox.getResource("mappings/particles.json");
|
||||
InputStream particleStream = FileUtils.getResource("mappings/particles.json");
|
||||
JsonNode particleEntries;
|
||||
try {
|
||||
particleEntries = Toolbox.JSON_MAPPER.readTree(particleStream);
|
||||
particleEntries = GeyserConnector.JSON_MAPPER.readTree(particleStream);
|
||||
} catch (Exception e) {
|
||||
throw new AssertionError("Unable to load particle map", e);
|
||||
}
|
||||
|
@ -69,10 +70,10 @@ public class EffectUtils {
|
|||
while (particlesIterator.hasNext()) {
|
||||
Map.Entry<String, JsonNode> entry = particlesIterator.next();
|
||||
try {
|
||||
setIdentifier(ParticleType.valueOf(entry.getKey().toUpperCase()), LevelEventType.valueOf(entry.getValue().asText().toUpperCase()));
|
||||
particleTypeMap.put(ParticleType.valueOf(entry.getKey().toUpperCase()), LevelEventType.valueOf(entry.getValue().asText().toUpperCase()));
|
||||
} catch (IllegalArgumentException e1) {
|
||||
try {
|
||||
setIdentifier(ParticleType.valueOf(entry.getKey().toUpperCase()), entry.getValue().asText());
|
||||
particleStringMap.put(ParticleType.valueOf(entry.getKey().toUpperCase()), entry.getValue().asText());
|
||||
GeyserConnector.getInstance().getLogger().debug("Force to map particle "
|
||||
+ entry.getKey()
|
||||
+ "=>"
|
||||
|
@ -85,10 +86,10 @@ public class EffectUtils {
|
|||
}
|
||||
|
||||
/* Load effects */
|
||||
InputStream effectsStream = Toolbox.getResource("mappings/effects.json");
|
||||
InputStream effectsStream = FileUtils.getResource("mappings/effects.json");
|
||||
JsonNode effects;
|
||||
try {
|
||||
effects = Toolbox.JSON_MAPPER.readTree(effectsStream);
|
||||
effects = GeyserConnector.JSON_MAPPER.readTree(effectsStream);
|
||||
} catch (Exception e) {
|
||||
throw new AssertionError("Unable to load effects mappings", e);
|
||||
}
|
||||
|
@ -112,14 +113,6 @@ public class EffectUtils {
|
|||
}
|
||||
}
|
||||
|
||||
public static void setIdentifier(ParticleType type, LevelEventType identifier) {
|
||||
particleTypeMap.put(type, identifier);
|
||||
}
|
||||
|
||||
public static void setIdentifier(ParticleType type, String identifier) {
|
||||
particleStringMap.put(type, identifier);
|
||||
}
|
||||
|
||||
public static LevelEventType getParticleLevelEventType(@NonNull ParticleType type) {
|
||||
return particleTypeMap.getOrDefault(type, null);
|
||||
}
|
||||
|
@ -127,5 +120,4 @@ public class EffectUtils {
|
|||
public static String getParticleString(@NonNull ParticleType type){
|
||||
return particleStringMap.getOrDefault(type, null);
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,69 @@
|
|||
/*
|
||||
* Copyright (c) 2019-2020 GeyserMC. http://geysermc.org
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*
|
||||
* @author GeyserMC
|
||||
* @link https://github.com/GeyserMC/Geyser
|
||||
*/
|
||||
|
||||
package org.geysermc.connector.network.translators.inventory;
|
||||
|
||||
import com.nukkitx.protocol.bedrock.data.InventoryActionData;
|
||||
import org.geysermc.connector.inventory.Inventory;
|
||||
import org.geysermc.connector.network.session.GeyserSession;
|
||||
import org.geysermc.connector.network.translators.inventory.updater.ChestInventoryUpdater;
|
||||
import org.geysermc.connector.network.translators.inventory.updater.InventoryUpdater;
|
||||
import org.geysermc.connector.utils.InventoryUtils;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public abstract class ChestInventoryTranslator extends BaseInventoryTranslator {
|
||||
private final InventoryUpdater updater;
|
||||
|
||||
public ChestInventoryTranslator(int size, int paddedSize) {
|
||||
super(size);
|
||||
this.updater = new ChestInventoryUpdater(paddedSize);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateInventory(GeyserSession session, Inventory inventory) {
|
||||
updater.updateInventory(this, session, inventory);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateSlot(GeyserSession session, Inventory inventory, int slot) {
|
||||
updater.updateSlot(this, session, inventory, slot);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void translateActions(GeyserSession session, Inventory inventory, List<InventoryActionData> actions) {
|
||||
for (InventoryActionData action : actions) {
|
||||
if (action.getSource().getContainerId() == inventory.getId()) {
|
||||
if (action.getSlot() >= size) {
|
||||
updateInventory(session, inventory);
|
||||
InventoryUtils.updateCursor(session);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
super.translateActions(session, inventory, actions);
|
||||
}
|
||||
}
|
|
@ -92,8 +92,11 @@ public class CraftingInventoryTranslator extends BaseInventoryTranslator {
|
|||
|
||||
@Override
|
||||
public int javaSlotToBedrock(int slot) {
|
||||
if (slot < size) {
|
||||
return slot == 0 ? 50 : slot + 31;
|
||||
}
|
||||
return super.javaSlotToBedrock(slot);
|
||||
}
|
||||
|
||||
@Override
|
||||
public SlotType getSlotType(int javaSlot) {
|
||||
|
|
|
@ -39,15 +39,13 @@ import org.geysermc.connector.network.translators.world.block.BlockTranslator;
|
|||
import org.geysermc.connector.network.translators.inventory.updater.ChestInventoryUpdater;
|
||||
import org.geysermc.connector.network.translators.inventory.updater.InventoryUpdater;
|
||||
|
||||
public class DoubleChestInventoryTranslator extends BaseInventoryTranslator {
|
||||
public class DoubleChestInventoryTranslator extends ChestInventoryTranslator {
|
||||
private final int blockId;
|
||||
private final InventoryUpdater updater;
|
||||
|
||||
public DoubleChestInventoryTranslator(int size) {
|
||||
super(size);
|
||||
super(size, 54);
|
||||
BlockState javaBlockState = BlockTranslator.getJavaBlockState("minecraft:chest[facing=north,type=single,waterlogged=false]");
|
||||
this.blockId = BlockTranslator.getBedrockBlockId(javaBlockState);
|
||||
this.updater = new ChestInventoryUpdater(54);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -128,14 +126,4 @@ public class DoubleChestInventoryTranslator extends BaseInventoryTranslator {
|
|||
blockPacket.setRuntimeId(BlockTranslator.getBedrockBlockId(realBlock));
|
||||
session.sendUpstreamPacket(blockPacket);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateInventory(GeyserSession session, Inventory inventory) {
|
||||
updater.updateInventory(this, session, inventory);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateSlot(GeyserSession session, Inventory inventory, int slot) {
|
||||
updater.updateSlot(this, session, inventory, slot);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -25,15 +25,51 @@
|
|||
|
||||
package org.geysermc.connector.network.translators.inventory;
|
||||
|
||||
import com.github.steveice10.mc.protocol.data.game.window.WindowType;
|
||||
import com.nukkitx.protocol.bedrock.data.ContainerType;
|
||||
import com.nukkitx.protocol.bedrock.data.InventoryActionData;
|
||||
import lombok.AllArgsConstructor;
|
||||
import org.geysermc.connector.inventory.Inventory;
|
||||
import org.geysermc.connector.network.session.GeyserSession;
|
||||
import org.geysermc.connector.network.translators.inventory.updater.ContainerInventoryUpdater;
|
||||
import org.geysermc.connector.network.translators.inventory.updater.InventoryUpdater;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
@AllArgsConstructor
|
||||
public abstract class InventoryTranslator {
|
||||
|
||||
public static final Map<WindowType, InventoryTranslator> INVENTORY_TRANSLATORS = new HashMap<WindowType, InventoryTranslator>() {
|
||||
{
|
||||
put(null, new PlayerInventoryTranslator()); //player inventory
|
||||
put(WindowType.GENERIC_9X1, new SingleChestInventoryTranslator(9));
|
||||
put(WindowType.GENERIC_9X2, new SingleChestInventoryTranslator(18));
|
||||
put(WindowType.GENERIC_9X3, new SingleChestInventoryTranslator(27));
|
||||
put(WindowType.GENERIC_9X4, new DoubleChestInventoryTranslator(36));
|
||||
put(WindowType.GENERIC_9X5, new DoubleChestInventoryTranslator(45));
|
||||
put(WindowType.GENERIC_9X6, new DoubleChestInventoryTranslator(54));
|
||||
put(WindowType.BREWING_STAND, new BrewingInventoryTranslator());
|
||||
put(WindowType.ANVIL, new AnvilInventoryTranslator());
|
||||
put(WindowType.CRAFTING, new CraftingInventoryTranslator());
|
||||
put(WindowType.GRINDSTONE, new GrindstoneInventoryTranslator());
|
||||
put(WindowType.MERCHANT, new MerchantInventoryTranslator());
|
||||
//put(WindowType.ENCHANTMENT, new EnchantmentInventoryTranslator()); //TODO
|
||||
|
||||
InventoryTranslator furnace = new FurnaceInventoryTranslator();
|
||||
put(WindowType.FURNACE, furnace);
|
||||
put(WindowType.BLAST_FURNACE, furnace);
|
||||
put(WindowType.SMOKER, furnace);
|
||||
|
||||
InventoryUpdater containerUpdater = new ContainerInventoryUpdater();
|
||||
put(WindowType.GENERIC_3X3, new BlockInventoryTranslator(9, "minecraft:dispenser[facing=north,triggered=false]", ContainerType.DISPENSER, containerUpdater));
|
||||
put(WindowType.HOPPER, new BlockInventoryTranslator(5, "minecraft:hopper[enabled=false,facing=down]", ContainerType.HOPPER, containerUpdater));
|
||||
put(WindowType.SHULKER_BOX, new BlockInventoryTranslator(27, "minecraft:shulker_box[facing=north]", ContainerType.CONTAINER, containerUpdater));
|
||||
//put(WindowType.BEACON, new BlockInventoryTranslator(1, "minecraft:beacon", ContainerType.BEACON)); //TODO
|
||||
}
|
||||
};
|
||||
|
||||
public final int size;
|
||||
|
||||
public abstract void prepareInventory(GeyserSession session, Inventory inventory);
|
||||
|
|
|
@ -36,10 +36,9 @@ import com.nukkitx.protocol.bedrock.packet.InventoryContentPacket;
|
|||
import com.nukkitx.protocol.bedrock.packet.InventorySlotPacket;
|
||||
import org.geysermc.connector.inventory.Inventory;
|
||||
import org.geysermc.connector.network.session.GeyserSession;
|
||||
import org.geysermc.connector.network.translators.Translators;
|
||||
import org.geysermc.connector.network.translators.inventory.action.InventoryActionDataTranslator;
|
||||
import org.geysermc.connector.network.translators.item.ItemTranslator;
|
||||
import org.geysermc.connector.utils.InventoryUtils;
|
||||
import org.geysermc.connector.utils.Toolbox;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
|
@ -60,11 +59,11 @@ public class PlayerInventoryTranslator extends InventoryTranslator {
|
|||
ItemData[] contents = new ItemData[36];
|
||||
// Inventory
|
||||
for (int i = 9; i < 36; i++) {
|
||||
contents[i] = Translators.getItemTranslator().translateToBedrock(session, inventory.getItem(i));
|
||||
contents[i] = ItemTranslator.translateToBedrock(session, inventory.getItem(i));
|
||||
}
|
||||
// Hotbar
|
||||
for (int i = 36; i < 45; i++) {
|
||||
contents[i - 36] = Translators.getItemTranslator().translateToBedrock(session, inventory.getItem(i));
|
||||
contents[i - 36] = ItemTranslator.translateToBedrock(session, inventory.getItem(i));
|
||||
}
|
||||
inventoryContentPacket.setContents(contents);
|
||||
session.sendUpstreamPacket(inventoryContentPacket);
|
||||
|
@ -74,7 +73,7 @@ public class PlayerInventoryTranslator extends InventoryTranslator {
|
|||
armorContentPacket.setContainerId(ContainerId.ARMOR);
|
||||
contents = new ItemData[4];
|
||||
for (int i = 5; i < 9; i++) {
|
||||
contents[i - 5] = Translators.getItemTranslator().translateToBedrock(session, inventory.getItem(i));
|
||||
contents[i - 5] = ItemTranslator.translateToBedrock(session, inventory.getItem(i));
|
||||
}
|
||||
armorContentPacket.setContents(contents);
|
||||
session.sendUpstreamPacket(armorContentPacket);
|
||||
|
@ -82,7 +81,7 @@ public class PlayerInventoryTranslator extends InventoryTranslator {
|
|||
// Offhand
|
||||
InventoryContentPacket offhandPacket = new InventoryContentPacket();
|
||||
offhandPacket.setContainerId(ContainerId.OFFHAND);
|
||||
offhandPacket.setContents(new ItemData[]{Translators.getItemTranslator().translateToBedrock(session, inventory.getItem(45))});
|
||||
offhandPacket.setContents(new ItemData[]{ItemTranslator.translateToBedrock(session, inventory.getItem(45))});
|
||||
session.sendUpstreamPacket(offhandPacket);
|
||||
}
|
||||
|
||||
|
@ -101,7 +100,7 @@ public class PlayerInventoryTranslator extends InventoryTranslator {
|
|||
if (session.getGameMode() == GameMode.CREATIVE) {
|
||||
slotPacket.setItem(UNUSUABLE_CRAFTING_SPACE_BLOCK);
|
||||
}else{
|
||||
slotPacket.setItem(Translators.getItemTranslator().translateToBedrock(session, inventory.getItem(i)));
|
||||
slotPacket.setItem(ItemTranslator.translateToBedrock(session, inventory.getItem(i)));
|
||||
}
|
||||
|
||||
session.sendUpstreamPacket(slotPacket);
|
||||
|
@ -126,12 +125,12 @@ public class PlayerInventoryTranslator extends InventoryTranslator {
|
|||
slotPacket.setContainerId(ContainerId.CURSOR);
|
||||
slotPacket.setSlot(slot + 27);
|
||||
}
|
||||
slotPacket.setItem(Translators.getItemTranslator().translateToBedrock(session, inventory.getItem(slot)));
|
||||
slotPacket.setItem(ItemTranslator.translateToBedrock(session, inventory.getItem(slot)));
|
||||
session.sendUpstreamPacket(slotPacket);
|
||||
} else if (slot == 45) {
|
||||
InventoryContentPacket offhandPacket = new InventoryContentPacket();
|
||||
offhandPacket.setContainerId(ContainerId.OFFHAND);
|
||||
offhandPacket.setContents(new ItemData[]{Translators.getItemTranslator().translateToBedrock(session, inventory.getItem(slot))});
|
||||
offhandPacket.setContents(new ItemData[]{ItemTranslator.translateToBedrock(session, inventory.getItem(slot))});
|
||||
session.sendUpstreamPacket(offhandPacket);
|
||||
}
|
||||
}
|
||||
|
@ -202,7 +201,7 @@ public class PlayerInventoryTranslator extends InventoryTranslator {
|
|||
if (action.getToItem().getId() == 0) {
|
||||
javaItem = new ItemStack(-1, 0, null);
|
||||
} else {
|
||||
javaItem = Translators.getItemTranslator().translateToJava(session, action.getToItem());
|
||||
javaItem = ItemTranslator.translateToJava(action.getToItem());
|
||||
}
|
||||
ClientCreativeInventoryActionPacket creativePacket = new ClientCreativeInventoryActionPacket(javaSlot, javaItem);
|
||||
session.sendDownstreamPacket(creativePacket);
|
||||
|
@ -210,13 +209,13 @@ public class PlayerInventoryTranslator extends InventoryTranslator {
|
|||
break;
|
||||
case ContainerId.CURSOR:
|
||||
if (action.getSlot() == 0) {
|
||||
session.getInventory().setCursor(Translators.getItemTranslator().translateToJava(session, action.getToItem()));
|
||||
session.getInventory().setCursor(ItemTranslator.translateToJava(action.getToItem()));
|
||||
}
|
||||
break;
|
||||
case ContainerId.NONE:
|
||||
if (action.getSource().getType() == InventorySource.Type.WORLD_INTERACTION
|
||||
&& action.getSource().getFlag() == InventorySource.Flag.DROP_ITEM) {
|
||||
javaItem = Translators.getItemTranslator().translateToJava(session, action.getToItem());
|
||||
javaItem = ItemTranslator.translateToJava(action.getToItem());
|
||||
ClientCreativeInventoryActionPacket creativeDropPacket = new ClientCreativeInventoryActionPacket(-1, javaItem);
|
||||
session.sendDownstreamPacket(creativeDropPacket);
|
||||
}
|
||||
|
|
|
@ -25,11 +25,35 @@
|
|||
|
||||
package org.geysermc.connector.network.translators.inventory;
|
||||
|
||||
import com.github.steveice10.mc.protocol.data.game.world.block.BlockState;
|
||||
import com.nukkitx.protocol.bedrock.data.ContainerType;
|
||||
import org.geysermc.connector.network.translators.inventory.updater.ChestInventoryUpdater;
|
||||
import org.geysermc.connector.inventory.Inventory;
|
||||
import org.geysermc.connector.network.session.GeyserSession;
|
||||
import org.geysermc.connector.network.translators.inventory.holder.BlockInventoryHolder;
|
||||
import org.geysermc.connector.network.translators.inventory.holder.InventoryHolder;
|
||||
import org.geysermc.connector.network.translators.world.block.BlockTranslator;
|
||||
|
||||
public class SingleChestInventoryTranslator extends ChestInventoryTranslator {
|
||||
private final InventoryHolder holder;
|
||||
|
||||
public class SingleChestInventoryTranslator extends BlockInventoryTranslator {
|
||||
public SingleChestInventoryTranslator(int size) {
|
||||
super(size, "minecraft:chest[facing=north,type=single,waterlogged=false]", ContainerType.CONTAINER, new ChestInventoryUpdater(27));
|
||||
super(size, 27);
|
||||
BlockState javaBlockState = BlockTranslator.getJavaBlockState("minecraft:chest[facing=north,type=single,waterlogged=false]");
|
||||
this.holder = new BlockInventoryHolder(BlockTranslator.getBedrockBlockId(javaBlockState), ContainerType.CONTAINER);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void prepareInventory(GeyserSession session, Inventory inventory) {
|
||||
holder.prepareInventory(this, session, inventory);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void openInventory(GeyserSession session, Inventory inventory) {
|
||||
holder.openInventory(this, session, inventory);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void closeInventory(GeyserSession session, Inventory inventory) {
|
||||
holder.closeInventory(this, session, inventory);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -38,9 +38,9 @@ import com.nukkitx.protocol.bedrock.data.InventorySource;
|
|||
import com.nukkitx.protocol.bedrock.data.ItemData;
|
||||
import org.geysermc.connector.inventory.Inventory;
|
||||
import org.geysermc.connector.network.session.GeyserSession;
|
||||
import org.geysermc.connector.network.translators.Translators;
|
||||
import org.geysermc.connector.network.translators.inventory.InventoryTranslator;
|
||||
import org.geysermc.connector.network.translators.inventory.SlotType;
|
||||
import org.geysermc.connector.network.translators.item.ItemTranslator;
|
||||
import org.geysermc.connector.utils.InventoryUtils;
|
||||
|
||||
import java.util.*;
|
||||
|
@ -61,13 +61,13 @@ public class InventoryActionDataTranslator {
|
|||
worldAction = action;
|
||||
} else if (action.getSource().getContainerId() == ContainerId.CURSOR && action.getSlot() == 0) {
|
||||
cursorAction = action;
|
||||
ItemData translatedCursor = Translators.getItemTranslator().translateToBedrock(session, session.getInventory().getCursor());
|
||||
ItemData translatedCursor = ItemTranslator.translateToBedrock(session, session.getInventory().getCursor());
|
||||
if (!translatedCursor.equals(action.getFromItem())) {
|
||||
refresh = true;
|
||||
}
|
||||
} else {
|
||||
containerAction = action;
|
||||
ItemData translatedItem = Translators.getItemTranslator().translateToBedrock(session, inventory.getItem(translator.bedrockSlotToJava(action)));
|
||||
ItemData translatedItem = ItemTranslator.translateToBedrock(session, inventory.getItem(translator.bedrockSlotToJava(action)));
|
||||
if (!translatedItem.equals(action.getFromItem())) {
|
||||
refresh = true;
|
||||
}
|
||||
|
@ -187,11 +187,12 @@ public class InventoryActionDataTranslator {
|
|||
} else if (translator.getSlotType(javaSlot) == SlotType.OUTPUT) {
|
||||
plan.add(Click.LEFT, javaSlot);
|
||||
} else {
|
||||
int cursorSlot = findTempSlot(inventory, session.getInventory().getCursor(), Collections.singletonList(javaSlot));
|
||||
int cursorSlot = findTempSlot(inventory, session.getInventory().getCursor(), Collections.singletonList(javaSlot), false);
|
||||
if (cursorSlot != -1) {
|
||||
plan.add(Click.LEFT, cursorSlot);
|
||||
} else {
|
||||
translator.updateInventory(session, inventory);
|
||||
InventoryUtils.updateCursor(session);
|
||||
return;
|
||||
}
|
||||
plan.add(Click.LEFT, javaSlot);
|
||||
|
@ -245,11 +246,15 @@ public class InventoryActionDataTranslator {
|
|||
|
||||
int cursorSlot = -1;
|
||||
if (session.getInventory().getCursor() != null) { //move cursor contents to a temporary slot
|
||||
cursorSlot = findTempSlot(inventory, session.getInventory().getCursor(), Arrays.asList(fromSlot, toSlot));
|
||||
cursorSlot = findTempSlot(inventory,
|
||||
session.getInventory().getCursor(),
|
||||
Arrays.asList(fromSlot, toSlot),
|
||||
translator.getSlotType(fromSlot) == SlotType.OUTPUT);
|
||||
if (cursorSlot != -1) {
|
||||
plan.add(Click.LEFT, cursorSlot);
|
||||
} else {
|
||||
translator.updateInventory(session, inventory);
|
||||
InventoryUtils.updateCursor(session);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
@ -298,7 +303,7 @@ public class InventoryActionDataTranslator {
|
|||
InventoryUtils.updateCursor(session);
|
||||
}
|
||||
|
||||
private static int findTempSlot(Inventory inventory, ItemStack item, List<Integer> slotBlacklist) {
|
||||
private static int findTempSlot(Inventory inventory, ItemStack item, List<Integer> slotBlacklist, boolean emptyOnly) {
|
||||
/*try and find a slot that can temporarily store the given item
|
||||
only look in the main inventory and hotbar
|
||||
only slots that are empty or contain a different type of item are valid*/
|
||||
|
@ -314,6 +319,9 @@ public class InventoryActionDataTranslator {
|
|||
ItemStack testItem = inventory.getItem(i);
|
||||
boolean acceptable = true;
|
||||
if (testItem != null) {
|
||||
if (emptyOnly) {
|
||||
continue;
|
||||
}
|
||||
for (ItemStack blacklistItem : itemBlacklist) {
|
||||
if (InventoryUtils.canStack(testItem, blacklistItem)) {
|
||||
acceptable = false;
|
||||
|
|
|
@ -31,8 +31,8 @@ import com.nukkitx.protocol.bedrock.packet.InventorySlotPacket;
|
|||
import lombok.AllArgsConstructor;
|
||||
import org.geysermc.connector.inventory.Inventory;
|
||||
import org.geysermc.connector.network.session.GeyserSession;
|
||||
import org.geysermc.connector.network.translators.Translators;
|
||||
import org.geysermc.connector.network.translators.inventory.InventoryTranslator;
|
||||
import org.geysermc.connector.network.translators.item.ItemTranslator;
|
||||
import org.geysermc.connector.utils.InventoryUtils;
|
||||
|
||||
@AllArgsConstructor
|
||||
|
@ -48,8 +48,8 @@ public class ChestInventoryUpdater extends InventoryUpdater {
|
|||
|
||||
ItemData[] bedrockItems = new ItemData[paddedSize];
|
||||
for (int i = 0; i < bedrockItems.length; i++) {
|
||||
if (i <= translator.size) {
|
||||
bedrockItems[i] = Translators.getItemTranslator().translateToBedrock(session, inventory.getItem(i));
|
||||
if (i < translator.size) {
|
||||
bedrockItems[i] = ItemTranslator.translateToBedrock(session, inventory.getItem(i));
|
||||
} else {
|
||||
bedrockItems[i] = UNUSUABLE_SPACE_BLOCK;
|
||||
}
|
||||
|
@ -69,7 +69,7 @@ public class ChestInventoryUpdater extends InventoryUpdater {
|
|||
InventorySlotPacket slotPacket = new InventorySlotPacket();
|
||||
slotPacket.setContainerId(inventory.getId());
|
||||
slotPacket.setSlot(translator.javaSlotToBedrock(javaSlot));
|
||||
slotPacket.setItem(Translators.getItemTranslator().translateToBedrock(session, inventory.getItem(javaSlot)));
|
||||
slotPacket.setItem(ItemTranslator.translateToBedrock(session, inventory.getItem(javaSlot)));
|
||||
session.sendUpstreamPacket(slotPacket);
|
||||
return true;
|
||||
}
|
||||
|
|
|
@ -30,8 +30,8 @@ import com.nukkitx.protocol.bedrock.packet.InventoryContentPacket;
|
|||
import com.nukkitx.protocol.bedrock.packet.InventorySlotPacket;
|
||||
import org.geysermc.connector.inventory.Inventory;
|
||||
import org.geysermc.connector.network.session.GeyserSession;
|
||||
import org.geysermc.connector.network.translators.Translators;
|
||||
import org.geysermc.connector.network.translators.inventory.InventoryTranslator;
|
||||
import org.geysermc.connector.network.translators.item.ItemTranslator;
|
||||
|
||||
public class ContainerInventoryUpdater extends InventoryUpdater {
|
||||
@Override
|
||||
|
@ -40,7 +40,7 @@ public class ContainerInventoryUpdater extends InventoryUpdater {
|
|||
|
||||
ItemData[] bedrockItems = new ItemData[translator.size];
|
||||
for (int i = 0; i < bedrockItems.length; i++) {
|
||||
bedrockItems[translator.javaSlotToBedrock(i)] = Translators.getItemTranslator().translateToBedrock(session, inventory.getItem(i));
|
||||
bedrockItems[translator.javaSlotToBedrock(i)] = ItemTranslator.translateToBedrock(session, inventory.getItem(i));
|
||||
}
|
||||
|
||||
InventoryContentPacket contentPacket = new InventoryContentPacket();
|
||||
|
@ -57,7 +57,7 @@ public class ContainerInventoryUpdater extends InventoryUpdater {
|
|||
InventorySlotPacket slotPacket = new InventorySlotPacket();
|
||||
slotPacket.setContainerId(inventory.getId());
|
||||
slotPacket.setSlot(translator.javaSlotToBedrock(javaSlot));
|
||||
slotPacket.setItem(Translators.getItemTranslator().translateToBedrock(session, inventory.getItem(javaSlot)));
|
||||
slotPacket.setItem(ItemTranslator.translateToBedrock(session, inventory.getItem(javaSlot)));
|
||||
session.sendUpstreamPacket(slotPacket);
|
||||
return true;
|
||||
}
|
||||
|
|
|
@ -29,8 +29,8 @@ import com.nukkitx.protocol.bedrock.data.ContainerId;
|
|||
import com.nukkitx.protocol.bedrock.packet.InventorySlotPacket;
|
||||
import org.geysermc.connector.inventory.Inventory;
|
||||
import org.geysermc.connector.network.session.GeyserSession;
|
||||
import org.geysermc.connector.network.translators.Translators;
|
||||
import org.geysermc.connector.network.translators.inventory.InventoryTranslator;
|
||||
import org.geysermc.connector.network.translators.item.ItemTranslator;
|
||||
|
||||
public class CursorInventoryUpdater extends InventoryUpdater {
|
||||
@Override
|
||||
|
@ -44,7 +44,7 @@ public class CursorInventoryUpdater extends InventoryUpdater {
|
|||
InventorySlotPacket slotPacket = new InventorySlotPacket();
|
||||
slotPacket.setContainerId(ContainerId.CURSOR);
|
||||
slotPacket.setSlot(bedrockSlot);
|
||||
slotPacket.setItem(Translators.getItemTranslator().translateToBedrock(session, inventory.getItem(i)));
|
||||
slotPacket.setItem(ItemTranslator.translateToBedrock(session, inventory.getItem(i)));
|
||||
session.sendUpstreamPacket(slotPacket);
|
||||
}
|
||||
}
|
||||
|
@ -57,7 +57,7 @@ public class CursorInventoryUpdater extends InventoryUpdater {
|
|||
InventorySlotPacket slotPacket = new InventorySlotPacket();
|
||||
slotPacket.setContainerId(ContainerId.CURSOR);
|
||||
slotPacket.setSlot(translator.javaSlotToBedrock(javaSlot));
|
||||
slotPacket.setItem(Translators.getItemTranslator().translateToBedrock(session, inventory.getItem(javaSlot)));
|
||||
slotPacket.setItem(ItemTranslator.translateToBedrock(session, inventory.getItem(javaSlot)));
|
||||
session.sendUpstreamPacket(slotPacket);
|
||||
return true;
|
||||
}
|
||||
|
|
|
@ -31,15 +31,15 @@ import com.nukkitx.protocol.bedrock.packet.InventoryContentPacket;
|
|||
import com.nukkitx.protocol.bedrock.packet.InventorySlotPacket;
|
||||
import org.geysermc.connector.inventory.Inventory;
|
||||
import org.geysermc.connector.network.session.GeyserSession;
|
||||
import org.geysermc.connector.network.translators.Translators;
|
||||
import org.geysermc.connector.network.translators.inventory.InventoryTranslator;
|
||||
import org.geysermc.connector.network.translators.item.ItemTranslator;
|
||||
|
||||
public abstract class InventoryUpdater {
|
||||
public void updateInventory(InventoryTranslator translator, GeyserSession session, Inventory inventory) {
|
||||
ItemData[] bedrockItems = new ItemData[36];
|
||||
for (int i = 0; i < 36; i++) {
|
||||
final int offset = i < 9 ? 27 : -9;
|
||||
bedrockItems[i] = Translators.getItemTranslator().translateToBedrock(session, inventory.getItem(translator.size + i + offset));
|
||||
bedrockItems[i] = ItemTranslator.translateToBedrock(session, inventory.getItem(translator.size + i + offset));
|
||||
}
|
||||
InventoryContentPacket contentPacket = new InventoryContentPacket();
|
||||
contentPacket.setContainerId(ContainerId.INVENTORY);
|
||||
|
@ -52,7 +52,7 @@ public abstract class InventoryUpdater {
|
|||
InventorySlotPacket slotPacket = new InventorySlotPacket();
|
||||
slotPacket.setContainerId(ContainerId.INVENTORY);
|
||||
slotPacket.setSlot(translator.javaSlotToBedrock(javaSlot));
|
||||
slotPacket.setItem(Translators.getItemTranslator().translateToBedrock(session, inventory.getItem(javaSlot)));
|
||||
slotPacket.setItem(ItemTranslator.translateToBedrock(session, inventory.getItem(javaSlot)));
|
||||
session.sendUpstreamPacket(slotPacket);
|
||||
return true;
|
||||
}
|
||||
|
|
|
@ -21,71 +21,65 @@
|
|||
*
|
||||
* @author GeyserMC
|
||||
* @link https://github.com/GeyserMC/Geyser
|
||||
*
|
||||
*/
|
||||
|
||||
package org.geysermc.connector.utils;
|
||||
package org.geysermc.connector.network.translators.item;
|
||||
|
||||
import com.fasterxml.jackson.core.type.TypeReference;
|
||||
import com.fasterxml.jackson.databind.DeserializationFeature;
|
||||
import com.fasterxml.jackson.databind.JsonNode;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import com.github.steveice10.mc.protocol.data.game.entity.metadata.ItemStack;
|
||||
import com.nukkitx.nbt.NbtUtils;
|
||||
import com.nukkitx.nbt.stream.NBTInputStream;
|
||||
import com.nukkitx.nbt.tag.CompoundTag;
|
||||
import com.nukkitx.protocol.bedrock.data.ItemData;
|
||||
import com.nukkitx.protocol.bedrock.packet.StartGamePacket;
|
||||
|
||||
import it.unimi.dsi.fastutil.ints.Int2ObjectMap;
|
||||
import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap;
|
||||
|
||||
import org.geysermc.connector.GeyserConnector;
|
||||
import org.geysermc.connector.network.translators.item.ItemEntry;
|
||||
import org.geysermc.connector.network.translators.item.ToolItemEntry;
|
||||
import org.geysermc.connector.network.translators.sound.SoundHandlerRegistry;
|
||||
import org.geysermc.connector.utils.FileUtils;
|
||||
|
||||
import java.io.*;
|
||||
import java.util.*;
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Base64;
|
||||
import java.util.HashMap;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
public class Toolbox {
|
||||
/**
|
||||
* Registry for anything item related.
|
||||
*/
|
||||
public class ItemRegistry {
|
||||
|
||||
private static final Map<String, ItemEntry> JAVA_IDENTIFIER_MAP = new HashMap<>();
|
||||
|
||||
public static final ObjectMapper JSON_MAPPER = new ObjectMapper().disable(DeserializationFeature.FAIL_ON_IGNORED_PROPERTIES);
|
||||
public static final CompoundTag BIOMES;
|
||||
public static final ItemData[] CREATIVE_ITEMS;
|
||||
|
||||
public static final List<StartGamePacket.ItemEntry> ITEMS = new ArrayList<>();
|
||||
|
||||
public static final Int2ObjectMap<ItemEntry> ITEM_ENTRIES = new Int2ObjectOpenHashMap<>();
|
||||
|
||||
public static CompoundTag ENTITY_IDENTIFIERS;
|
||||
// Shield ID, used in Entity.java
|
||||
public static final int SHIELD = 829;
|
||||
// Boat ID, used in BedrockInventoryTransactionTranslator.java
|
||||
public static final int BOAT = 333;
|
||||
|
||||
public static int BARRIER_INDEX = 0;
|
||||
|
||||
public static void init() {
|
||||
// no-op
|
||||
}
|
||||
|
||||
static {
|
||||
/* Load biomes */
|
||||
InputStream biomestream = GeyserConnector.class.getClassLoader().getResourceAsStream("bedrock/biome_definitions.dat");
|
||||
if (biomestream == null) {
|
||||
throw new AssertionError("Unable to find bedrock/biome_definitions.dat");
|
||||
}
|
||||
|
||||
CompoundTag biomesTag;
|
||||
|
||||
try (NBTInputStream biomenbtInputStream = NbtUtils.createNetworkReader(biomestream)){
|
||||
biomesTag = (CompoundTag) biomenbtInputStream.readTag();
|
||||
BIOMES = biomesTag;
|
||||
} catch (Exception ex) {
|
||||
GeyserConnector.getInstance().getLogger().warning("Failed to get biomes from biome definitions, is there something wrong with the file?");
|
||||
throw new AssertionError(ex);
|
||||
}
|
||||
|
||||
/* Load item palette */
|
||||
InputStream stream = getResource("bedrock/items.json");
|
||||
InputStream stream = FileUtils.getResource("bedrock/items.json");
|
||||
|
||||
TypeReference<List<JsonNode>> itemEntriesType = new TypeReference<List<JsonNode>>() {
|
||||
};
|
||||
|
||||
List<JsonNode> itemEntries;
|
||||
try {
|
||||
itemEntries = JSON_MAPPER.readValue(stream, itemEntriesType);
|
||||
itemEntries = GeyserConnector.JSON_MAPPER.readValue(stream, itemEntriesType);
|
||||
} catch (Exception e) {
|
||||
throw new AssertionError("Unable to load Bedrock runtime item IDs", e);
|
||||
}
|
||||
|
@ -94,11 +88,11 @@ public class Toolbox {
|
|||
ITEMS.add(new StartGamePacket.ItemEntry(entry.get("name").textValue(), (short) entry.get("id").intValue()));
|
||||
}
|
||||
|
||||
stream = getResource("mappings/items.json");
|
||||
stream = FileUtils.getResource("mappings/items.json");
|
||||
|
||||
JsonNode items;
|
||||
try {
|
||||
items = JSON_MAPPER.readTree(stream);
|
||||
items = GeyserConnector.JSON_MAPPER.readTree(stream);
|
||||
} catch (Exception e) {
|
||||
throw new AssertionError("Unable to load Java runtime item IDs", e);
|
||||
}
|
||||
|
@ -139,22 +133,12 @@ public class Toolbox {
|
|||
itemIndex++;
|
||||
}
|
||||
|
||||
// Load particle/effect mappings
|
||||
EffectUtils.init();
|
||||
// Load sound mappings
|
||||
SoundUtils.init();
|
||||
// Load the locale data
|
||||
LocaleUtils.init();
|
||||
|
||||
// Load sound handlers
|
||||
SoundHandlerRegistry.init();
|
||||
|
||||
/* Load creative items */
|
||||
stream = getResource("bedrock/creative_items.json");
|
||||
stream = FileUtils.getResource("bedrock/creative_items.json");
|
||||
|
||||
JsonNode creativeItemEntries;
|
||||
try {
|
||||
creativeItemEntries = JSON_MAPPER.readTree(stream).get("items");
|
||||
creativeItemEntries = GeyserConnector.JSON_MAPPER.readTree(stream).get("items");
|
||||
} catch (Exception e) {
|
||||
throw new AssertionError("Unable to load creative items", e);
|
||||
}
|
||||
|
@ -179,33 +163,51 @@ public class Toolbox {
|
|||
}
|
||||
}
|
||||
CREATIVE_ITEMS = creativeItems.toArray(new ItemData[0]);
|
||||
|
||||
|
||||
/* Load entity identifiers */
|
||||
stream = Toolbox.getResource("bedrock/entity_identifiers.dat");
|
||||
|
||||
try (NBTInputStream nbtInputStream = NbtUtils.createNetworkReader(stream)) {
|
||||
ENTITY_IDENTIFIERS = (CompoundTag) nbtInputStream.readTag();
|
||||
} catch (Exception e) {
|
||||
throw new AssertionError("Unable to get entities from entity identifiers", e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get an InputStream for the given resource path, throws AssertionError if resource is not found
|
||||
* Gets an {@link ItemEntry} from the given {@link ItemStack}.
|
||||
*
|
||||
* @param resource Resource to get
|
||||
* @return InputStream of the given resource
|
||||
* @param stack the item stack
|
||||
* @return an item entry from the given item stack
|
||||
*/
|
||||
public static InputStream getResource(String resource) {
|
||||
InputStream stream = Toolbox.class.getClassLoader().getResourceAsStream(resource);
|
||||
if (stream == null) {
|
||||
throw new AssertionError("Unable to find resource: " + resource);
|
||||
}
|
||||
return stream;
|
||||
public static ItemEntry getItem(ItemStack stack) {
|
||||
return ITEM_ENTRIES.get(stack.getId());
|
||||
}
|
||||
|
||||
public static void init() {
|
||||
// no-op
|
||||
/**
|
||||
* Gets an {@link ItemEntry} from the given {@link ItemData}.
|
||||
*
|
||||
* @param data the item data
|
||||
* @return an item entry from the given item data
|
||||
*/
|
||||
public static ItemEntry getItem(ItemData data) {
|
||||
for (ItemEntry itemEntry : ITEM_ENTRIES.values()) {
|
||||
if (itemEntry.getBedrockId() == data.getId() && (itemEntry.getBedrockData() == data.getDamage() || itemEntry.getJavaIdentifier().endsWith("potion"))) {
|
||||
return itemEntry;
|
||||
}
|
||||
}
|
||||
// If item find was unsuccessful first time, we try again while ignoring damage
|
||||
// Fixes piston, sticky pistons, dispensers and droppers turning into air from creative inventory
|
||||
for (ItemEntry itemEntry : ITEM_ENTRIES.values()) {
|
||||
if (itemEntry.getBedrockId() == data.getId()) {
|
||||
return itemEntry;
|
||||
}
|
||||
}
|
||||
|
||||
GeyserConnector.getInstance().getLogger().debug("Missing mapping for bedrock item " + data.getId() + ":" + data.getDamage());
|
||||
return ItemEntry.AIR;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets an {@link ItemEntry} from the given Minecraft: Java Edition
|
||||
* block state identifier.
|
||||
*
|
||||
* @param javaIdentifier the block state identifier
|
||||
* @return an item entry from the given java edition identifier
|
||||
*/
|
||||
public static ItemEntry getItemEntry(String javaIdentifier) {
|
||||
return JAVA_IDENTIFIER_MAP.computeIfAbsent(javaIdentifier, key -> ITEM_ENTRIES.values()
|
||||
.stream().filter(itemEntry -> itemEntry.getJavaIdentifier().equals(key)).findFirst().orElse(null));
|
||||
}
|
||||
}
|
|
@ -21,35 +21,47 @@
|
|||
*
|
||||
* @author GeyserMC
|
||||
* @link https://github.com/GeyserMC/Geyser
|
||||
*
|
||||
*/
|
||||
|
||||
package org.geysermc.connector.network.translators.item;
|
||||
|
||||
import com.github.steveice10.mc.protocol.data.game.entity.metadata.ItemStack;
|
||||
import com.github.steveice10.mc.protocol.data.message.Message;
|
||||
import com.nukkitx.nbt.CompoundTagBuilder;
|
||||
import com.github.steveice10.opennbt.tag.builtin.*;
|
||||
import com.nukkitx.nbt.tag.CompoundTag;
|
||||
import com.nukkitx.nbt.tag.Tag;
|
||||
import com.nukkitx.protocol.bedrock.data.ItemData;
|
||||
|
||||
import it.unimi.dsi.fastutil.ints.Int2ObjectMap;
|
||||
import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap;
|
||||
import org.geysermc.connector.GeyserConnector;
|
||||
|
||||
import org.geysermc.connector.network.session.GeyserSession;
|
||||
import org.geysermc.connector.network.translators.*;
|
||||
import org.geysermc.connector.utils.Toolbox;
|
||||
import org.geysermc.connector.network.translators.ItemRemapper;
|
||||
import org.geysermc.connector.utils.MessageUtils;
|
||||
import org.reflections.Reflections;
|
||||
|
||||
import java.util.*;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Comparator;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
public class ItemTranslator {
|
||||
public abstract class ItemTranslator {
|
||||
|
||||
private Int2ObjectMap<ItemStackTranslator> itemTranslators = new Int2ObjectOpenHashMap();
|
||||
private List<NbtItemStackTranslator> nbtItemTranslators;
|
||||
private Map<String, ItemEntry> javaIdentifierMap = new HashMap<>();
|
||||
private static final Int2ObjectMap<ItemTranslator> ITEM_STACK_TRANSLATORS = new Int2ObjectOpenHashMap<>();
|
||||
private static final List<NbtItemStackTranslator> NBT_TRANSLATORS;
|
||||
|
||||
// Shield ID, used in Entity.java
|
||||
public static final int SHIELD = 829;
|
||||
protected ItemTranslator() {
|
||||
}
|
||||
|
||||
public void init() {
|
||||
public static void init() {
|
||||
// no-op
|
||||
}
|
||||
|
||||
static {
|
||||
/* Load item translators */
|
||||
Reflections ref = new Reflections("org.geysermc.connector.network.translators.item");
|
||||
|
||||
Map<NbtItemStackTranslator, Integer> loadedNbtItemTranslators = new HashMap<>();
|
||||
|
@ -64,34 +76,33 @@ public class ItemTranslator {
|
|||
loadedNbtItemTranslators.put(nbtItemTranslator, priority);
|
||||
continue;
|
||||
}
|
||||
ItemStackTranslator itemStackTranslator = (ItemStackTranslator) clazz.newInstance();
|
||||
ItemTranslator itemStackTranslator = (ItemTranslator) clazz.newInstance();
|
||||
List<ItemEntry> appliedItems = itemStackTranslator.getAppliedItems();
|
||||
for (ItemEntry item : appliedItems) {
|
||||
ItemStackTranslator registered = itemTranslators.get(item.getJavaId());
|
||||
ItemTranslator registered = ITEM_STACK_TRANSLATORS.get(item.getJavaId());
|
||||
if (registered != null) {
|
||||
GeyserConnector.getInstance().getLogger().error("Could not instantiate annotated item translator " + clazz.getCanonicalName() + "." +
|
||||
" Item translator " + registered.getClass().getCanonicalName() + " is already registered for the item " + item.getJavaIdentifier());
|
||||
continue;
|
||||
}
|
||||
itemTranslators.put(item.getJavaId(), itemStackTranslator);
|
||||
ITEM_STACK_TRANSLATORS.put(item.getJavaId(), itemStackTranslator);
|
||||
}
|
||||
} catch (InstantiationException | IllegalAccessException e) {
|
||||
GeyserConnector.getInstance().getLogger().error("Could not instantiate annotated item translator " + clazz.getCanonicalName() + ".");
|
||||
}
|
||||
}
|
||||
|
||||
nbtItemTranslators = loadedNbtItemTranslators.keySet().stream()
|
||||
.sorted(Comparator.comparingInt(value -> loadedNbtItemTranslators.get(value))).collect(Collectors.toList());
|
||||
NBT_TRANSLATORS = loadedNbtItemTranslators.keySet().stream().sorted(Comparator.comparingInt(loadedNbtItemTranslators::get)).collect(Collectors.toList());
|
||||
}
|
||||
|
||||
public ItemStack translateToJava(GeyserSession session, ItemData data) {
|
||||
public static ItemStack translateToJava(ItemData data) {
|
||||
if (data == null) {
|
||||
return new ItemStack(0);
|
||||
}
|
||||
ItemEntry javaItem = getItem(data);
|
||||
ItemEntry javaItem = ItemRegistry.getItem(data);
|
||||
|
||||
ItemStack itemStack;
|
||||
ItemStackTranslator itemStackTranslator = itemTranslators.get(javaItem.getJavaId());
|
||||
ItemTranslator itemStackTranslator = ITEM_STACK_TRANSLATORS.get(javaItem.getJavaId());
|
||||
if (itemStackTranslator != null) {
|
||||
itemStack = itemStackTranslator.translateToJava(data, javaItem);
|
||||
} else {
|
||||
|
@ -99,7 +110,7 @@ public class ItemTranslator {
|
|||
}
|
||||
|
||||
if (itemStack != null && itemStack.getNbt() != null) {
|
||||
for (NbtItemStackTranslator translator : nbtItemTranslators) {
|
||||
for (NbtItemStackTranslator translator : NBT_TRANSLATORS) {
|
||||
if (translator.acceptItem(javaItem)) {
|
||||
translator.translateToJava(itemStack.getNbt(), javaItem);
|
||||
}
|
||||
|
@ -108,56 +119,270 @@ public class ItemTranslator {
|
|||
return itemStack;
|
||||
}
|
||||
|
||||
public ItemData translateToBedrock(GeyserSession session, ItemStack stack) {
|
||||
public static ItemData translateToBedrock(GeyserSession session, ItemStack stack) {
|
||||
if (stack == null) {
|
||||
return ItemData.AIR;
|
||||
}
|
||||
|
||||
ItemEntry bedrockItem = getItem(stack);
|
||||
ItemEntry bedrockItem = ItemRegistry.getItem(stack);
|
||||
|
||||
ItemStack itemStack = new ItemStack(stack.getId(), stack.getAmount(), stack.getNbt() != null ? stack.getNbt().clone() : null);
|
||||
|
||||
if (itemStack.getNbt() != null) {
|
||||
for (NbtItemStackTranslator translator : nbtItemTranslators) {
|
||||
for (NbtItemStackTranslator translator : NBT_TRANSLATORS) {
|
||||
if (translator.acceptItem(bedrockItem)) {
|
||||
translator.translateToBedrock(itemStack.getNbt(), bedrockItem);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ItemStackTranslator itemStackTranslator = itemTranslators.get(bedrockItem.getJavaId());
|
||||
ItemData itemData;
|
||||
ItemTranslator itemStackTranslator = ITEM_STACK_TRANSLATORS.get(bedrockItem.getJavaId());
|
||||
if (itemStackTranslator != null) {
|
||||
return itemStackTranslator.translateToBedrock(itemStack, bedrockItem);
|
||||
itemData = itemStackTranslator.translateToBedrock(itemStack, bedrockItem);
|
||||
} else {
|
||||
return DEFAULT_TRANSLATOR.translateToBedrock(itemStack, bedrockItem);
|
||||
itemData = DEFAULT_TRANSLATOR.translateToBedrock(itemStack, bedrockItem);
|
||||
}
|
||||
|
||||
|
||||
// Get the display name of the item
|
||||
CompoundTag tag = itemData.getTag();
|
||||
if (tag != null) {
|
||||
CompoundTag display = tag.getCompound("display");
|
||||
if (display != null) {
|
||||
String name = display.getString("Name");
|
||||
|
||||
// Check if its a message to translate
|
||||
if (MessageUtils.isMessage(name)) {
|
||||
// Get the translated name
|
||||
name = MessageUtils.getTranslatedBedrockMessage(Message.fromString(name), session.getClientData().getLanguageCode());
|
||||
|
||||
// Build the new display tag
|
||||
CompoundTagBuilder displayBuilder = display.toBuilder();
|
||||
displayBuilder.stringTag("Name", name);
|
||||
|
||||
// Build the new root tag
|
||||
CompoundTagBuilder builder = tag.toBuilder();
|
||||
builder.tag(displayBuilder.build("display"));
|
||||
|
||||
// Create a new item with the original data + updated name
|
||||
itemData = ItemData.of(itemData.getId(), itemData.getDamage(), itemData.getCount(), builder.buildRootTag());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public ItemEntry getItem(ItemStack stack) {
|
||||
return Toolbox.ITEM_ENTRIES.get(stack.getId());
|
||||
return itemData;
|
||||
}
|
||||
|
||||
public ItemEntry getItem(ItemData data) {
|
||||
for (ItemEntry itemEntry : Toolbox.ITEM_ENTRIES.values()) {
|
||||
if (itemEntry.getBedrockId() == data.getId() && (itemEntry.getBedrockData() == data.getDamage() || itemEntry.getJavaIdentifier().endsWith("potion"))) {
|
||||
return itemEntry;
|
||||
private static final ItemTranslator DEFAULT_TRANSLATOR = new ItemTranslator() {
|
||||
@Override
|
||||
public List<ItemEntry> getAppliedItems() {
|
||||
return null;
|
||||
}
|
||||
};
|
||||
|
||||
public ItemData translateToBedrock(ItemStack itemStack, ItemEntry itemEntry) {
|
||||
if (itemStack == null) {
|
||||
return ItemData.AIR;
|
||||
}
|
||||
// If item find was unsuccessful first time, we try again while ignoring damage
|
||||
// Fixes piston, sticky pistons, dispensers and droppers turning into air from creative inventory
|
||||
for (ItemEntry itemEntry : Toolbox.ITEM_ENTRIES.values()) {
|
||||
if (itemEntry.getBedrockId() == data.getId()) {
|
||||
return itemEntry;
|
||||
if (itemStack.getNbt() == null) {
|
||||
return ItemData.of(itemEntry.getBedrockId(), (short) itemEntry.getBedrockData(), itemStack.getAmount());
|
||||
}
|
||||
return ItemData.of(itemEntry.getBedrockId(), (short) itemEntry.getBedrockData(), itemStack.getAmount(), this.translateNbtToBedrock(itemStack.getNbt()));
|
||||
}
|
||||
|
||||
public ItemStack translateToJava(ItemData itemData, ItemEntry itemEntry) {
|
||||
if (itemData == null) return null;
|
||||
if (itemData.getTag() == null) {
|
||||
return new ItemStack(itemEntry.getJavaId(), itemData.getCount(), new com.github.steveice10.opennbt.tag.builtin.CompoundTag(""));
|
||||
}
|
||||
return new ItemStack(itemEntry.getJavaId(), itemData.getCount(), this.translateToJavaNBT(itemData.getTag()));
|
||||
}
|
||||
|
||||
public abstract List<ItemEntry> getAppliedItems();
|
||||
|
||||
public CompoundTag translateNbtToBedrock(com.github.steveice10.opennbt.tag.builtin.CompoundTag tag) {
|
||||
Map<String, Tag<?>> javaValue = new HashMap<>();
|
||||
if (tag.getValue() != null && !tag.getValue().isEmpty()) {
|
||||
for (String str : tag.getValue().keySet()) {
|
||||
com.github.steveice10.opennbt.tag.builtin.Tag javaTag = tag.get(str);
|
||||
com.nukkitx.nbt.tag.Tag<?> translatedTag = translateToBedrockNBT(javaTag);
|
||||
if (translatedTag == null)
|
||||
continue;
|
||||
|
||||
javaValue.put(translatedTag.getName(), translatedTag);
|
||||
}
|
||||
}
|
||||
|
||||
GeyserConnector.getInstance().getLogger().debug("Missing mapping for bedrock item " + data.getId() + ":" + data.getDamage());
|
||||
return ItemEntry.AIR;
|
||||
return new CompoundTag(tag.getName(), javaValue);
|
||||
}
|
||||
|
||||
public ItemEntry getItemEntry(String javaIdentifier) {
|
||||
return javaIdentifierMap.computeIfAbsent(javaIdentifier, key -> Toolbox.ITEM_ENTRIES.values()
|
||||
.stream().filter(itemEntry -> itemEntry.getJavaIdentifier().equals(key)).findFirst().orElse(null));
|
||||
private Tag<?> translateToBedrockNBT(com.github.steveice10.opennbt.tag.builtin.Tag tag) {
|
||||
if (tag instanceof ByteArrayTag) {
|
||||
ByteArrayTag byteArrayTag = (ByteArrayTag) tag;
|
||||
return new com.nukkitx.nbt.tag.ByteArrayTag(byteArrayTag.getName(), byteArrayTag.getValue());
|
||||
}
|
||||
|
||||
if (tag instanceof ByteTag) {
|
||||
ByteTag byteTag = (ByteTag) tag;
|
||||
return new com.nukkitx.nbt.tag.ByteTag(byteTag.getName(), byteTag.getValue());
|
||||
}
|
||||
|
||||
if (tag instanceof DoubleTag) {
|
||||
DoubleTag doubleTag = (DoubleTag) tag;
|
||||
return new com.nukkitx.nbt.tag.DoubleTag(doubleTag.getName(), doubleTag.getValue());
|
||||
}
|
||||
|
||||
if (tag instanceof FloatTag) {
|
||||
FloatTag floatTag = (FloatTag) tag;
|
||||
return new com.nukkitx.nbt.tag.FloatTag(floatTag.getName(), floatTag.getValue());
|
||||
}
|
||||
|
||||
if (tag instanceof IntArrayTag) {
|
||||
IntArrayTag intArrayTag = (IntArrayTag) tag;
|
||||
return new com.nukkitx.nbt.tag.IntArrayTag(intArrayTag.getName(), intArrayTag.getValue());
|
||||
}
|
||||
|
||||
if (tag instanceof IntTag) {
|
||||
IntTag intTag = (IntTag) tag;
|
||||
return new com.nukkitx.nbt.tag.IntTag(intTag.getName(), intTag.getValue());
|
||||
}
|
||||
|
||||
if (tag instanceof LongArrayTag) {
|
||||
LongArrayTag longArrayTag = (LongArrayTag) tag;
|
||||
return new com.nukkitx.nbt.tag.LongArrayTag(longArrayTag.getName(), longArrayTag.getValue());
|
||||
}
|
||||
|
||||
if (tag instanceof LongTag) {
|
||||
LongTag longTag = (LongTag) tag;
|
||||
return new com.nukkitx.nbt.tag.LongTag(longTag.getName(), longTag.getValue());
|
||||
}
|
||||
|
||||
if (tag instanceof ShortTag) {
|
||||
ShortTag shortTag = (ShortTag) tag;
|
||||
return new com.nukkitx.nbt.tag.ShortTag(shortTag.getName(), shortTag.getValue());
|
||||
}
|
||||
|
||||
if (tag instanceof StringTag) {
|
||||
StringTag stringTag = (StringTag) tag;
|
||||
return new com.nukkitx.nbt.tag.StringTag(stringTag.getName(), stringTag.getValue());
|
||||
}
|
||||
|
||||
if (tag instanceof ListTag) {
|
||||
ListTag listTag = (ListTag) tag;
|
||||
|
||||
List<Tag<?>> tagList = new ArrayList<>();
|
||||
for (com.github.steveice10.opennbt.tag.builtin.Tag value : listTag) {
|
||||
tagList.add(translateToBedrockNBT(value));
|
||||
}
|
||||
Class<?> clazz = CompoundTag.class;
|
||||
if (!tagList.isEmpty()) {
|
||||
clazz = tagList.get(0).getClass();
|
||||
}
|
||||
return new com.nukkitx.nbt.tag.ListTag(listTag.getName(), clazz, tagList);
|
||||
}
|
||||
|
||||
if (tag instanceof com.github.steveice10.opennbt.tag.builtin.CompoundTag) {
|
||||
com.github.steveice10.opennbt.tag.builtin.CompoundTag compoundTag = (com.github.steveice10.opennbt.tag.builtin.CompoundTag) tag;
|
||||
|
||||
return translateNbtToBedrock(compoundTag);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public com.github.steveice10.opennbt.tag.builtin.CompoundTag translateToJavaNBT(com.nukkitx.nbt.tag.CompoundTag tag) {
|
||||
com.github.steveice10.opennbt.tag.builtin.CompoundTag javaTag = new com.github.steveice10.opennbt.tag.builtin.CompoundTag(tag.getName());
|
||||
Map<String, com.github.steveice10.opennbt.tag.builtin.Tag> javaValue = javaTag.getValue();
|
||||
if (tag.getValue() != null && !tag.getValue().isEmpty()) {
|
||||
for (String str : tag.getValue().keySet()) {
|
||||
Tag<?> bedrockTag = tag.get(str);
|
||||
com.github.steveice10.opennbt.tag.builtin.Tag translatedTag = translateToJavaNBT(bedrockTag);
|
||||
if (translatedTag == null)
|
||||
continue;
|
||||
|
||||
javaValue.put(translatedTag.getName(), translatedTag);
|
||||
}
|
||||
}
|
||||
|
||||
javaTag.setValue(javaValue);
|
||||
return javaTag;
|
||||
}
|
||||
|
||||
private com.github.steveice10.opennbt.tag.builtin.Tag translateToJavaNBT(com.nukkitx.nbt.tag.Tag<?> tag) {
|
||||
if (tag instanceof com.nukkitx.nbt.tag.ByteArrayTag) {
|
||||
com.nukkitx.nbt.tag.ByteArrayTag byteArrayTag = (com.nukkitx.nbt.tag.ByteArrayTag) tag;
|
||||
return new ByteArrayTag(byteArrayTag.getName(), byteArrayTag.getValue());
|
||||
}
|
||||
|
||||
if (tag instanceof com.nukkitx.nbt.tag.ByteTag) {
|
||||
com.nukkitx.nbt.tag.ByteTag byteTag = (com.nukkitx.nbt.tag.ByteTag) tag;
|
||||
return new ByteTag(byteTag.getName(), byteTag.getValue());
|
||||
}
|
||||
|
||||
if (tag instanceof com.nukkitx.nbt.tag.DoubleTag) {
|
||||
com.nukkitx.nbt.tag.DoubleTag doubleTag = (com.nukkitx.nbt.tag.DoubleTag) tag;
|
||||
return new DoubleTag(doubleTag.getName(), doubleTag.getValue());
|
||||
}
|
||||
|
||||
if (tag instanceof com.nukkitx.nbt.tag.FloatTag) {
|
||||
com.nukkitx.nbt.tag.FloatTag floatTag = (com.nukkitx.nbt.tag.FloatTag) tag;
|
||||
return new FloatTag(floatTag.getName(), floatTag.getValue());
|
||||
}
|
||||
|
||||
if (tag instanceof com.nukkitx.nbt.tag.IntArrayTag) {
|
||||
com.nukkitx.nbt.tag.IntArrayTag intArrayTag = (com.nukkitx.nbt.tag.IntArrayTag) tag;
|
||||
return new IntArrayTag(intArrayTag.getName(), intArrayTag.getValue());
|
||||
}
|
||||
|
||||
if (tag instanceof com.nukkitx.nbt.tag.IntTag) {
|
||||
com.nukkitx.nbt.tag.IntTag intTag = (com.nukkitx.nbt.tag.IntTag) tag;
|
||||
return new IntTag(intTag.getName(), intTag.getValue());
|
||||
}
|
||||
|
||||
if (tag instanceof com.nukkitx.nbt.tag.LongArrayTag) {
|
||||
com.nukkitx.nbt.tag.LongArrayTag longArrayTag = (com.nukkitx.nbt.tag.LongArrayTag) tag;
|
||||
return new LongArrayTag(longArrayTag.getName(), longArrayTag.getValue());
|
||||
}
|
||||
|
||||
if (tag instanceof com.nukkitx.nbt.tag.LongTag) {
|
||||
com.nukkitx.nbt.tag.LongTag longTag = (com.nukkitx.nbt.tag.LongTag) tag;
|
||||
return new LongTag(longTag.getName(), longTag.getValue());
|
||||
}
|
||||
|
||||
if (tag instanceof com.nukkitx.nbt.tag.ShortTag) {
|
||||
com.nukkitx.nbt.tag.ShortTag shortTag = (com.nukkitx.nbt.tag.ShortTag) tag;
|
||||
return new ShortTag(shortTag.getName(), shortTag.getValue());
|
||||
}
|
||||
|
||||
if (tag instanceof com.nukkitx.nbt.tag.StringTag) {
|
||||
com.nukkitx.nbt.tag.StringTag stringTag = (com.nukkitx.nbt.tag.StringTag) tag;
|
||||
return new StringTag(stringTag.getName(), stringTag.getValue());
|
||||
}
|
||||
|
||||
if (tag instanceof com.nukkitx.nbt.tag.ListTag) {
|
||||
com.nukkitx.nbt.tag.ListTag<?> listTag = (com.nukkitx.nbt.tag.ListTag<?>) tag;
|
||||
|
||||
List<com.github.steveice10.opennbt.tag.builtin.Tag> tags = new ArrayList<>();
|
||||
|
||||
for (Object value : listTag.getValue()) {
|
||||
if (!(value instanceof com.nukkitx.nbt.tag.Tag))
|
||||
continue;
|
||||
|
||||
com.nukkitx.nbt.tag.Tag<?> tagValue = (com.nukkitx.nbt.tag.Tag<?>) value;
|
||||
com.github.steveice10.opennbt.tag.builtin.Tag javaTag = translateToJavaNBT(tagValue);
|
||||
if (javaTag != null)
|
||||
tags.add(javaTag);
|
||||
}
|
||||
return new ListTag(listTag.getName(), tags);
|
||||
}
|
||||
|
||||
if (tag instanceof com.nukkitx.nbt.tag.CompoundTag) {
|
||||
com.nukkitx.nbt.tag.CompoundTag compoundTag = (com.nukkitx.nbt.tag.CompoundTag) tag;
|
||||
return translateToJavaNBT(compoundTag);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -205,10 +430,4 @@ public class ItemTranslator {
|
|||
return true;
|
||||
}
|
||||
|
||||
private static final ItemStackTranslator DEFAULT_TRANSLATOR = new ItemStackTranslator() {
|
||||
@Override
|
||||
public List<ItemEntry> getAppliedItems() {
|
||||
return null;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
|
|
@ -0,0 +1,45 @@
|
|||
/*
|
||||
* Copyright (c) 2019-2020 GeyserMC. http://geysermc.org
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*
|
||||
* @author GeyserMC
|
||||
* @link https://github.com/GeyserMC/Geyser
|
||||
*
|
||||
*/
|
||||
|
||||
package org.geysermc.connector.network.translators.item;
|
||||
|
||||
import com.github.steveice10.opennbt.tag.builtin.CompoundTag;
|
||||
|
||||
public class NbtItemStackTranslator {
|
||||
|
||||
public void translateToBedrock(CompoundTag itemTag, ItemEntry itemEntry) {
|
||||
|
||||
}
|
||||
|
||||
public void translateToJava(CompoundTag itemTag, ItemEntry itemEntry) {
|
||||
|
||||
}
|
||||
|
||||
public boolean acceptItem(ItemEntry itemEntry) {
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,167 @@
|
|||
/*
|
||||
* Copyright (c) 2019-2020 GeyserMC. http://geysermc.org
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*
|
||||
* @author GeyserMC
|
||||
* @link https://github.com/GeyserMC/Geyser
|
||||
*/
|
||||
|
||||
package org.geysermc.connector.network.translators.item.translators;
|
||||
|
||||
import com.github.steveice10.mc.protocol.data.game.entity.metadata.ItemStack;
|
||||
import com.github.steveice10.opennbt.tag.builtin.CompoundTag;
|
||||
import com.github.steveice10.opennbt.tag.builtin.IntTag;
|
||||
import com.github.steveice10.opennbt.tag.builtin.ListTag;
|
||||
import com.github.steveice10.opennbt.tag.builtin.StringTag;
|
||||
import com.github.steveice10.opennbt.tag.builtin.Tag;
|
||||
import com.nukkitx.nbt.CompoundTagBuilder;
|
||||
import com.nukkitx.protocol.bedrock.data.ItemData;
|
||||
import org.geysermc.connector.network.translators.ItemRemapper;
|
||||
import org.geysermc.connector.network.translators.item.ItemRegistry;
|
||||
import org.geysermc.connector.network.translators.item.ItemTranslator;
|
||||
import org.geysermc.connector.network.translators.item.ItemEntry;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
@ItemRemapper
|
||||
public class BannerTranslator extends ItemTranslator {
|
||||
|
||||
private List<ItemEntry> appliedItems;
|
||||
|
||||
public BannerTranslator() {
|
||||
appliedItems = ItemRegistry.ITEM_ENTRIES.values().stream().filter(entry -> entry.getJavaIdentifier().endsWith("banner")).collect(Collectors.toList());
|
||||
}
|
||||
|
||||
@Override
|
||||
public ItemData translateToBedrock(ItemStack itemStack, ItemEntry itemEntry) {
|
||||
if (itemStack.getNbt() == null) return super.translateToBedrock(itemStack, itemEntry);
|
||||
|
||||
ItemData itemData = super.translateToBedrock(itemStack, itemEntry);
|
||||
|
||||
CompoundTag blockEntityTag = itemStack.getNbt().get("BlockEntityTag");
|
||||
if (blockEntityTag.contains("Patterns")) {
|
||||
ListTag patterns = blockEntityTag.get("Patterns");
|
||||
|
||||
CompoundTagBuilder builder = itemData.getTag().toBuilder();
|
||||
builder.tag(convertBannerPattern(patterns));
|
||||
|
||||
itemData = ItemData.of(itemData.getId(), itemData.getDamage(), itemData.getCount(), builder.buildRootTag());
|
||||
}
|
||||
|
||||
return itemData;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ItemStack translateToJava(ItemData itemData, ItemEntry itemEntry) {
|
||||
if (itemData.getTag() == null) return super.translateToJava(itemData, itemEntry);
|
||||
|
||||
ItemStack itemStack = super.translateToJava(itemData, itemEntry);
|
||||
|
||||
com.nukkitx.nbt.tag.CompoundTag nbtTag = itemData.getTag();
|
||||
if (nbtTag.contains("Patterns")) {
|
||||
com.nukkitx.nbt.tag.ListTag<?> patterns = nbtTag.get("Patterns");
|
||||
|
||||
CompoundTag blockEntityTag = new CompoundTag("BlockEntityTag");
|
||||
blockEntityTag.put(convertBannerPattern(patterns));
|
||||
|
||||
itemStack.getNbt().put(blockEntityTag);
|
||||
}
|
||||
|
||||
return itemStack;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<ItemEntry> getAppliedItems() {
|
||||
return appliedItems;
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert a list of patterns from Java nbt to Bedrock nbt
|
||||
*
|
||||
* @param patterns The patterns to convert
|
||||
* @return The new converted patterns
|
||||
*/
|
||||
public static com.nukkitx.nbt.tag.ListTag convertBannerPattern(ListTag patterns) {
|
||||
List<com.nukkitx.nbt.tag.CompoundTag> tagsList = new ArrayList<>();
|
||||
for (com.github.steveice10.opennbt.tag.builtin.Tag patternTag : patterns.getValue()) {
|
||||
com.nukkitx.nbt.tag.CompoundTag newPatternTag = getBedrockBannerPattern((CompoundTag) patternTag);
|
||||
if (newPatternTag != null) {
|
||||
tagsList.add(newPatternTag);
|
||||
}
|
||||
}
|
||||
|
||||
return new com.nukkitx.nbt.tag.ListTag<>("Patterns", com.nukkitx.nbt.tag.CompoundTag.class, tagsList);
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert the Java edition banner pattern nbt to Bedrock edition, null if the pattern doesn't exist
|
||||
*
|
||||
* @param pattern Java edition pattern nbt
|
||||
* @return The Bedrock edition format pattern nbt
|
||||
*/
|
||||
public static com.nukkitx.nbt.tag.CompoundTag getBedrockBannerPattern(CompoundTag pattern) {
|
||||
String patternName = (String) pattern.get("Pattern").getValue();
|
||||
|
||||
// Return null if its the globe pattern as it doesn't exist on bedrock
|
||||
if (patternName.equals("glb")) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return CompoundTagBuilder.builder()
|
||||
.intTag("Color", 15 - (int) pattern.get("Color").getValue())
|
||||
.stringTag("Pattern", (String) pattern.get("Pattern").getValue())
|
||||
.stringTag("Pattern", patternName)
|
||||
.buildRootTag();
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert a list of patterns from Bedrock nbt to Java nbt
|
||||
*
|
||||
* @param patterns The patterns to convert
|
||||
* @return The new converted patterns
|
||||
*/
|
||||
public static ListTag convertBannerPattern(com.nukkitx.nbt.tag.ListTag<?> patterns) {
|
||||
List<Tag> tagsList = new ArrayList<>();
|
||||
for (Object patternTag : patterns.getValue()) {
|
||||
CompoundTag newPatternTag = getJavaBannerPattern((com.nukkitx.nbt.tag.CompoundTag) patternTag);
|
||||
tagsList.add(newPatternTag);
|
||||
}
|
||||
|
||||
return new ListTag("Patterns", tagsList);
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert the Bedrock edition banner pattern nbt to Java edition
|
||||
*
|
||||
* @param pattern Bedorck edition pattern nbt
|
||||
* @return The Java edition format pattern nbt
|
||||
*/
|
||||
public static CompoundTag getJavaBannerPattern(com.nukkitx.nbt.tag.CompoundTag pattern) {
|
||||
Map<String, Tag> tags = new HashMap<>();
|
||||
tags.put("Color", new IntTag("Color", 15 - pattern.getInt("Color")));
|
||||
tags.put("Pattern", new StringTag("Pattern", pattern.getString("Pattern")));
|
||||
|
||||
return new CompoundTag("", tags);
|
||||
}
|
||||
}
|
|
@ -30,22 +30,22 @@ import com.github.steveice10.opennbt.tag.builtin.StringTag;
|
|||
import com.github.steveice10.opennbt.tag.builtin.Tag;
|
||||
import com.nukkitx.protocol.bedrock.data.ItemData;
|
||||
import org.geysermc.connector.GeyserConnector;
|
||||
import org.geysermc.connector.network.translators.ItemStackTranslator;
|
||||
import org.geysermc.connector.network.translators.item.ItemRegistry;
|
||||
import org.geysermc.connector.network.translators.item.ItemTranslator;
|
||||
import org.geysermc.connector.network.translators.ItemRemapper;
|
||||
import org.geysermc.connector.network.translators.item.ItemEntry;
|
||||
import org.geysermc.connector.network.translators.item.Potion;
|
||||
import org.geysermc.connector.utils.Toolbox;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
@ItemRemapper
|
||||
public class PotionTranslator extends ItemStackTranslator {
|
||||
public class PotionTranslator extends ItemTranslator {
|
||||
|
||||
private List<ItemEntry> appliedItems;
|
||||
|
||||
public PotionTranslator() {
|
||||
appliedItems = Toolbox.ITEM_ENTRIES.values().stream().filter(entry -> entry.getJavaIdentifier().endsWith("potion")).collect(Collectors.toList());
|
||||
appliedItems = ItemRegistry.ITEM_ENTRIES.values().stream().filter(entry -> entry.getJavaIdentifier().endsWith("potion")).collect(Collectors.toList());
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -34,7 +34,7 @@ import net.kyori.text.TextComponent;
|
|||
import net.kyori.text.serializer.gson.GsonComponentSerializer;
|
||||
import net.kyori.text.serializer.legacy.LegacyComponentSerializer;
|
||||
import org.geysermc.connector.network.translators.ItemRemapper;
|
||||
import org.geysermc.connector.network.translators.NbtItemStackTranslator;
|
||||
import org.geysermc.connector.network.translators.item.NbtItemStackTranslator;
|
||||
import org.geysermc.connector.network.translators.item.ItemEntry;
|
||||
import org.geysermc.connector.utils.MessageUtils;
|
||||
|
||||
|
@ -46,7 +46,9 @@ public class BasicItemTranslator extends NbtItemStackTranslator {
|
|||
|
||||
@Override
|
||||
public void translateToBedrock(CompoundTag itemTag, ItemEntry itemEntry) {
|
||||
if (itemTag.contains("display")) {
|
||||
if (!itemTag.contains("display")) {
|
||||
return;
|
||||
}
|
||||
CompoundTag displayTag = itemTag.get("display");
|
||||
if (displayTag.contains("Name")) {
|
||||
StringTag nameTag = displayTag.get("Name");
|
||||
|
@ -69,11 +71,12 @@ public class BasicItemTranslator extends NbtItemStackTranslator {
|
|||
displayTag.put(new ListTag("Lore", lore));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void translateToJava(CompoundTag itemTag, ItemEntry itemEntry) {
|
||||
if (itemTag.contains("display")) {
|
||||
if (!itemTag.contains("display")) {
|
||||
return;
|
||||
}
|
||||
CompoundTag displayTag = itemTag.get("display");
|
||||
if (displayTag.contains("Name")) {
|
||||
StringTag nameTag = displayTag.get("Name");
|
||||
|
@ -90,7 +93,6 @@ public class BasicItemTranslator extends NbtItemStackTranslator {
|
|||
displayTag.put(new ListTag("Lore", lore));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private String toJavaMessage(StringTag tag) {
|
||||
String message = tag.getValue();
|
||||
|
|
|
@ -30,7 +30,7 @@ import com.github.steveice10.opennbt.tag.builtin.ListTag;
|
|||
import com.github.steveice10.opennbt.tag.builtin.StringTag;
|
||||
import com.github.steveice10.opennbt.tag.builtin.Tag;
|
||||
import org.geysermc.connector.network.translators.ItemRemapper;
|
||||
import org.geysermc.connector.network.translators.NbtItemStackTranslator;
|
||||
import org.geysermc.connector.network.translators.item.NbtItemStackTranslator;
|
||||
import org.geysermc.connector.network.translators.item.ItemEntry;
|
||||
import org.geysermc.connector.utils.MessageUtils;
|
||||
|
||||
|
@ -42,7 +42,9 @@ public class BookPagesTranslator extends NbtItemStackTranslator {
|
|||
|
||||
@Override
|
||||
public void translateToBedrock(CompoundTag itemTag, ItemEntry itemEntry) {
|
||||
if (itemTag.contains("pages")) {
|
||||
if (!itemTag.contains("pages")) {
|
||||
return;
|
||||
}
|
||||
List<Tag> pages = new ArrayList<>();
|
||||
ListTag pagesTag = itemTag.get("pages");
|
||||
for (Tag tag : pagesTag.getValue()) {
|
||||
|
@ -53,18 +55,19 @@ public class BookPagesTranslator extends NbtItemStackTranslator {
|
|||
|
||||
CompoundTag pageTag = new CompoundTag("");
|
||||
pageTag.put(new StringTag("photoname", ""));
|
||||
pageTag.put(new StringTag("text", MessageUtils.getBedrockMessage(textTag.getValue())));
|
||||
pageTag.put(new StringTag("text", MessageUtils.getBedrockMessageLenient(textTag.getValue())));
|
||||
pages.add(pageTag);
|
||||
}
|
||||
|
||||
itemTag.remove("pages");
|
||||
itemTag.put(new ListTag("pages", pages));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void translateToJava(CompoundTag itemTag, ItemEntry itemEntry) {
|
||||
if (itemTag.contains("pages")) {
|
||||
if (!itemTag.contains("pages")) {
|
||||
return;
|
||||
}
|
||||
List<Tag> pages = new ArrayList<>();
|
||||
ListTag pagesTag = itemTag.get("pages");
|
||||
for (Tag tag : pagesTag.getValue()) {
|
||||
|
@ -80,5 +83,4 @@ public class BookPagesTranslator extends NbtItemStackTranslator {
|
|||
itemTag.remove("pages");
|
||||
itemTag.put(new ListTag("pages", pages));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,78 @@
|
|||
/*
|
||||
* Copyright (c) 2019-2020 GeyserMC. http://geysermc.org
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*
|
||||
* @author GeyserMC
|
||||
* @link https://github.com/GeyserMC/Geyser
|
||||
*/
|
||||
|
||||
package org.geysermc.connector.network.translators.item.translators.nbt;
|
||||
|
||||
import com.github.steveice10.opennbt.tag.builtin.ByteTag;
|
||||
import com.github.steveice10.opennbt.tag.builtin.CompoundTag;
|
||||
import com.github.steveice10.opennbt.tag.builtin.ListTag;
|
||||
import com.github.steveice10.opennbt.tag.builtin.StringTag;
|
||||
import org.geysermc.connector.network.translators.ItemRemapper;
|
||||
import org.geysermc.connector.network.translators.item.NbtItemStackTranslator;
|
||||
import org.geysermc.connector.network.translators.item.ItemEntry;
|
||||
|
||||
@ItemRemapper
|
||||
public class CrossbowTranslator extends NbtItemStackTranslator {
|
||||
|
||||
@Override
|
||||
public void translateToBedrock(CompoundTag itemTag, ItemEntry itemEntry) {
|
||||
if (itemTag.get("ChargedProjectiles") != null) {
|
||||
ListTag chargedProjectiles = itemTag.get("ChargedProjectiles");
|
||||
if (!chargedProjectiles.getValue().isEmpty()) {
|
||||
CompoundTag projectile = (CompoundTag) chargedProjectiles.getValue().get(0);
|
||||
|
||||
CompoundTag newProjectile = new CompoundTag("chargedItem");
|
||||
newProjectile.put(new ByteTag("Count", (byte) projectile.get("Count").getValue()));
|
||||
newProjectile.put(new StringTag("Name", (String) projectile.get("id").getValue()));
|
||||
|
||||
// Not sure what this is for
|
||||
newProjectile.put(new ByteTag("Damage", (byte) 0));
|
||||
|
||||
itemTag.put(newProjectile);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void translateToJava(CompoundTag itemTag, ItemEntry itemEntry) {
|
||||
if (itemTag.get("chargedItem") != null) {
|
||||
CompoundTag chargedItem = itemTag.get("chargedItem");
|
||||
|
||||
CompoundTag newProjectile = new CompoundTag("");
|
||||
newProjectile.put(new ByteTag("Count", (byte) chargedItem.get("Count").getValue()));
|
||||
newProjectile.put(new StringTag("id", (String) chargedItem.get("Name").getValue()));
|
||||
|
||||
ListTag chargedProjectiles = new ListTag("ChargedProjectiles");
|
||||
chargedProjectiles.add(newProjectile);
|
||||
|
||||
itemTag.put(chargedProjectiles);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean acceptItem(ItemEntry itemEntry) {
|
||||
return "minecraft:crossbow".equals(itemEntry.getJavaIdentifier());
|
||||
}
|
||||
}
|
|
@ -29,7 +29,7 @@ import com.github.steveice10.opennbt.tag.builtin.CompoundTag;
|
|||
import com.github.steveice10.opennbt.tag.builtin.ListTag;
|
||||
import com.github.steveice10.opennbt.tag.builtin.Tag;
|
||||
import org.geysermc.connector.network.translators.ItemRemapper;
|
||||
import org.geysermc.connector.network.translators.NbtItemStackTranslator;
|
||||
import org.geysermc.connector.network.translators.item.NbtItemStackTranslator;
|
||||
import org.geysermc.connector.network.translators.item.ItemEntry;
|
||||
|
||||
@ItemRemapper(priority = 1)
|
||||
|
@ -37,7 +37,9 @@ public class EnchantedBookTranslator extends NbtItemStackTranslator {
|
|||
|
||||
@Override
|
||||
public void translateToBedrock(CompoundTag itemTag, ItemEntry itemEntry) {
|
||||
if (itemTag.contains("StoredEnchantments")) {
|
||||
if (!itemTag.contains("StoredEnchantments")) {
|
||||
return;
|
||||
}
|
||||
Tag enchTag = itemTag.get("StoredEnchantments");
|
||||
if (enchTag instanceof ListTag) {
|
||||
enchTag = new ListTag("Enchantments", ((ListTag) enchTag).getValue());
|
||||
|
@ -45,11 +47,12 @@ public class EnchantedBookTranslator extends NbtItemStackTranslator {
|
|||
itemTag.put(enchTag);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void translateToJava(CompoundTag itemTag, ItemEntry itemEntry) {
|
||||
if (itemTag.contains("Enchantments")) {
|
||||
if (!itemTag.contains("Enchantments")) {
|
||||
return;
|
||||
}
|
||||
Tag enchTag = itemTag.get("Enchantments");
|
||||
if (enchTag instanceof ListTag) {
|
||||
enchTag = new ListTag("StoredEnchantments", ((ListTag) enchTag).getValue());
|
||||
|
@ -57,7 +60,6 @@ public class EnchantedBookTranslator extends NbtItemStackTranslator {
|
|||
itemTag.put(enchTag);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean acceptItem(ItemEntry itemEntry) {
|
||||
|
|
|
@ -28,7 +28,7 @@ package org.geysermc.connector.network.translators.item.translators.nbt;
|
|||
import com.github.steveice10.opennbt.tag.builtin.*;
|
||||
import org.geysermc.connector.GeyserConnector;
|
||||
import org.geysermc.connector.network.translators.ItemRemapper;
|
||||
import org.geysermc.connector.network.translators.NbtItemStackTranslator;
|
||||
import org.geysermc.connector.network.translators.item.NbtItemStackTranslator;
|
||||
import org.geysermc.connector.network.translators.item.Enchantment;
|
||||
import org.geysermc.connector.network.translators.item.ItemEntry;
|
||||
|
||||
|
@ -73,7 +73,10 @@ public class EnchantmentTranslator extends NbtItemStackTranslator {
|
|||
|
||||
@Override
|
||||
public void translateToJava(CompoundTag itemTag, ItemEntry itemEntry) {
|
||||
if (itemTag.contains("ench")) {
|
||||
if (!itemTag.contains("ench")) {
|
||||
return;
|
||||
}
|
||||
|
||||
ListTag enchantmentTag = itemTag.get("ench");
|
||||
List<Tag> enchantments = new ArrayList<>();
|
||||
List<Tag> storedEnchantments = new ArrayList<>();
|
||||
|
@ -115,7 +118,6 @@ public class EnchantmentTranslator extends NbtItemStackTranslator {
|
|||
}
|
||||
itemTag.remove("ench");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private CompoundTag remapEnchantment(CompoundTag tag) {
|
||||
|
|
|
@ -0,0 +1,157 @@
|
|||
/*
|
||||
* Copyright (c) 2019-2020 GeyserMC. http://geysermc.org
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*
|
||||
* @author GeyserMC
|
||||
* @link https://github.com/GeyserMC/Geyser
|
||||
*/
|
||||
|
||||
package org.geysermc.connector.network.translators.item.translators.nbt;
|
||||
|
||||
import com.github.steveice10.opennbt.tag.builtin.*;
|
||||
import org.geysermc.connector.network.translators.ItemRemapper;
|
||||
import org.geysermc.connector.network.translators.item.ItemEntry;
|
||||
import org.geysermc.connector.network.translators.item.NbtItemStackTranslator;
|
||||
import org.geysermc.connector.utils.FireworkColor;
|
||||
import org.geysermc.connector.utils.MathUtils;
|
||||
|
||||
@ItemRemapper
|
||||
public class FireworkTranslator extends NbtItemStackTranslator {
|
||||
|
||||
@Override
|
||||
public void translateToBedrock(CompoundTag itemTag, ItemEntry itemEntry) {
|
||||
if (!itemTag.contains("Fireworks")) {
|
||||
return;
|
||||
}
|
||||
|
||||
CompoundTag fireworks = itemTag.get("Fireworks");
|
||||
if (fireworks.get("Flight") != null) {
|
||||
fireworks.put(new ByteTag("Flight", MathUtils.convertByte(fireworks.get("Flight").getValue())));
|
||||
}
|
||||
|
||||
ListTag explosions = fireworks.get("Explosions");
|
||||
if (explosions == null) {
|
||||
return;
|
||||
}
|
||||
for (Tag effect : explosions.getValue()) {
|
||||
CompoundTag effectData = (CompoundTag) effect;
|
||||
|
||||
CompoundTag newEffectData = new CompoundTag("");
|
||||
|
||||
if (effectData.get("Type") != null) {
|
||||
newEffectData.put(new ByteTag("FireworkType", MathUtils.convertByte(effectData.get("Type").getValue())));
|
||||
}
|
||||
|
||||
if (effectData.get("Colors") != null) {
|
||||
int[] oldColors = (int[]) effectData.get("Colors").getValue();
|
||||
byte[] colors = new byte[oldColors.length];
|
||||
|
||||
int i = 0;
|
||||
for (int color : oldColors) {
|
||||
colors[i++] = FireworkColor.fromJavaID(color).getBedrockID();
|
||||
}
|
||||
|
||||
newEffectData.put(new ByteArrayTag("FireworkColor", colors));
|
||||
}
|
||||
|
||||
if (effectData.get("FadeColors") != null) {
|
||||
int[] oldColors = (int[]) effectData.get("FadeColors").getValue();
|
||||
byte[] colors = new byte[oldColors.length];
|
||||
|
||||
int i = 0;
|
||||
for (int color : oldColors) {
|
||||
colors[i++] = FireworkColor.fromJavaID(color).getBedrockID();
|
||||
}
|
||||
|
||||
newEffectData.put(new ByteArrayTag("FireworkFade", colors));
|
||||
}
|
||||
|
||||
if (effectData.get("Trail") != null) {
|
||||
newEffectData.put(new ByteTag("FireworkTrail", MathUtils.convertByte(effectData.get("Trail").getValue())));
|
||||
}
|
||||
|
||||
if (effectData.get("Flicker") != null) {
|
||||
newEffectData.put(new ByteTag("FireworkFlicker", MathUtils.convertByte(effectData.get("Flicker").getValue())));
|
||||
}
|
||||
|
||||
explosions.remove(effect);
|
||||
explosions.add(newEffectData);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void translateToJava(CompoundTag itemTag, ItemEntry itemEntry) {
|
||||
CompoundTag fireworks = itemTag.get("Fireworks");
|
||||
if (fireworks.get("Flight") != null) {
|
||||
fireworks.put(new ByteTag("Flight", MathUtils.convertByte(fireworks.get("Flight").getValue())));
|
||||
}
|
||||
|
||||
ListTag explosions = fireworks.get("Explosions");
|
||||
for (Tag effect : explosions.getValue()) {
|
||||
CompoundTag effectData = (CompoundTag) effect;
|
||||
|
||||
CompoundTag newEffectData = new CompoundTag("");
|
||||
|
||||
if (effectData.get("FireworkType") != null) {
|
||||
newEffectData.put(new ByteTag("Type", MathUtils.convertByte(effectData.get("FireworkType").getValue())));
|
||||
}
|
||||
|
||||
if (effectData.get("FireworkColor") != null) {
|
||||
byte[] oldColors = (byte[]) effectData.get("FireworkColor").getValue();
|
||||
int[] colors = new int[oldColors.length];
|
||||
|
||||
int i = 0;
|
||||
for (byte color : oldColors) {
|
||||
colors[i++] = FireworkColor.fromBedrockID(color).getJavaID();
|
||||
}
|
||||
|
||||
newEffectData.put(new IntArrayTag("Colors", colors));
|
||||
}
|
||||
|
||||
if (effectData.get("FireworkFade") != null) {
|
||||
byte[] oldColors = (byte[]) effectData.get("FireworkFade").getValue();
|
||||
int[] colors = new int[oldColors.length];
|
||||
|
||||
int i = 0;
|
||||
for (byte color : oldColors) {
|
||||
colors[i++] = FireworkColor.fromBedrockID(color).getJavaID();
|
||||
}
|
||||
|
||||
newEffectData.put(new IntArrayTag("FadeColors", colors));
|
||||
}
|
||||
|
||||
if (effectData.get("FireworkTrail") != null) {
|
||||
newEffectData.put(new ByteTag("Trail", MathUtils.convertByte(effectData.get("FireworkTrail").getValue())));
|
||||
}
|
||||
|
||||
if (effectData.get("FireworkFlicker") != null) {
|
||||
newEffectData.put(new ByteTag("Flicker", MathUtils.convertByte(effectData.get("FireworkFlicker").getValue())));
|
||||
}
|
||||
|
||||
explosions.remove(effect);
|
||||
explosions.add(newEffectData);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean acceptItem(ItemEntry itemEntry) {
|
||||
return "minecraft:firework_rocket".equals(itemEntry.getJavaIdentifier());
|
||||
}
|
||||
}
|
|
@ -28,7 +28,7 @@ package org.geysermc.connector.network.translators.item.translators.nbt;
|
|||
import com.github.steveice10.opennbt.tag.builtin.CompoundTag;
|
||||
import com.github.steveice10.opennbt.tag.builtin.IntTag;
|
||||
import org.geysermc.connector.network.translators.ItemRemapper;
|
||||
import org.geysermc.connector.network.translators.NbtItemStackTranslator;
|
||||
import org.geysermc.connector.network.translators.item.NbtItemStackTranslator;
|
||||
import org.geysermc.connector.network.translators.item.ItemEntry;
|
||||
|
||||
@ItemRemapper
|
||||
|
@ -38,7 +38,9 @@ public class LeatherArmorTranslator extends NbtItemStackTranslator {
|
|||
|
||||
@Override
|
||||
public void translateToBedrock(CompoundTag itemTag, ItemEntry itemEntry) {
|
||||
if (itemTag.contains("display")) {
|
||||
if (!itemTag.contains("display")) {
|
||||
return;
|
||||
}
|
||||
CompoundTag displayTag = itemTag.get("display");
|
||||
if (displayTag.contains("color")) {
|
||||
IntTag color = displayTag.get("color");
|
||||
|
@ -48,11 +50,12 @@ public class LeatherArmorTranslator extends NbtItemStackTranslator {
|
|||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void translateToJava(CompoundTag itemTag, ItemEntry itemEntry) {
|
||||
if (itemTag.contains("customColor")) {
|
||||
if (!itemTag.contains("customColor")) {
|
||||
return;
|
||||
}
|
||||
IntTag color = itemTag.get("customColor");
|
||||
CompoundTag displayTag = itemTag.get("display");
|
||||
if (displayTag == null) {
|
||||
|
@ -61,7 +64,6 @@ public class LeatherArmorTranslator extends NbtItemStackTranslator {
|
|||
displayTag.put(color);
|
||||
itemTag.remove("customColor");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean acceptItem(ItemEntry itemEntry) {
|
||||
|
|
|
@ -25,11 +25,12 @@
|
|||
|
||||
package org.geysermc.connector.network.translators.item.translators.nbt;
|
||||
|
||||
import com.github.steveice10.opennbt.tag.builtin.ByteTag;
|
||||
import com.github.steveice10.opennbt.tag.builtin.CompoundTag;
|
||||
import com.github.steveice10.opennbt.tag.builtin.IntTag;
|
||||
import com.github.steveice10.opennbt.tag.builtin.StringTag;
|
||||
import org.geysermc.connector.network.translators.ItemRemapper;
|
||||
import org.geysermc.connector.network.translators.NbtItemStackTranslator;
|
||||
import org.geysermc.connector.network.translators.item.NbtItemStackTranslator;
|
||||
import org.geysermc.connector.network.translators.item.ItemEntry;
|
||||
|
||||
@ItemRemapper
|
||||
|
@ -42,6 +43,7 @@ public class MapItemTranslator extends NbtItemStackTranslator {
|
|||
if (mapId != null) {
|
||||
itemTag.put(new StringTag("map_uuid", mapId.getValue().toString()));
|
||||
itemTag.put(new IntTag("map_name_index", mapId.getValue()));
|
||||
itemTag.put(new ByteTag("map_display_players", (byte) 1));
|
||||
itemTag.remove("map");
|
||||
}
|
||||
}
|
||||
|
|
|
@ -32,8 +32,6 @@ import org.geysermc.connector.network.translators.Translator;
|
|||
|
||||
import com.github.steveice10.mc.protocol.packet.ingame.server.ServerBossBarPacket;
|
||||
|
||||
import java.awt.*;
|
||||
|
||||
@Translator(packet = ServerBossBarPacket.class)
|
||||
public class JavaBossBarTranslator extends PacketTranslator<ServerBossBarPacket> {
|
||||
@Override
|
||||
|
|
|
@ -43,9 +43,14 @@ import org.geysermc.connector.network.translators.Translator;
|
|||
import java.util.*;
|
||||
|
||||
@Translator(packet = ServerDeclareCommandsPacket.class)
|
||||
public class JavaServerDeclareCommandsTranslator extends PacketTranslator<ServerDeclareCommandsPacket> {
|
||||
public class JavaDeclareCommandsTranslator extends PacketTranslator<ServerDeclareCommandsPacket> {
|
||||
@Override
|
||||
public void translate(ServerDeclareCommandsPacket packet, GeyserSession session) {
|
||||
// Don't send command suggestions if they are disabled
|
||||
if (!session.getConnector().getConfig().isCommandSuggestions()) {
|
||||
session.getConnector().getLogger().debug("Not sending command suggestions as they are disabled.");
|
||||
return;
|
||||
}
|
||||
List<CommandData> commandData = new ArrayList<>();
|
||||
Int2ObjectMap<String> commands = new Int2ObjectOpenHashMap<>();
|
||||
Int2ObjectMap<List<CommandNode>> commandArgs = new Int2ObjectOpenHashMap<>();
|
|
@ -42,9 +42,9 @@ import lombok.EqualsAndHashCode;
|
|||
import org.geysermc.connector.network.session.GeyserSession;
|
||||
import org.geysermc.connector.network.translators.PacketTranslator;
|
||||
import org.geysermc.connector.network.translators.Translator;
|
||||
import org.geysermc.connector.network.translators.Translators;
|
||||
import org.geysermc.connector.network.translators.item.ItemEntry;
|
||||
import org.geysermc.connector.utils.Toolbox;
|
||||
import org.geysermc.connector.network.translators.item.ItemRegistry;
|
||||
import org.geysermc.connector.network.translators.item.ItemTranslator;
|
||||
|
||||
import java.util.*;
|
||||
import java.util.stream.Collectors;
|
||||
|
@ -64,7 +64,7 @@ public class JavaDeclareRecipesTranslator extends PacketTranslator<ServerDeclare
|
|||
switch (recipe.getType()) {
|
||||
case CRAFTING_SHAPELESS: {
|
||||
ShapelessRecipeData shapelessRecipeData = (ShapelessRecipeData) recipe.getData();
|
||||
ItemData output = Translators.getItemTranslator().translateToBedrock(session, shapelessRecipeData.getResult());
|
||||
ItemData output = ItemTranslator.translateToBedrock(session, shapelessRecipeData.getResult());
|
||||
output = ItemData.of(output.getId(), output.getDamage(), output.getCount()); //strip NBT
|
||||
ItemData[][] inputCombinations = combinations(session, shapelessRecipeData.getIngredients());
|
||||
for (ItemData[] inputs : inputCombinations) {
|
||||
|
@ -76,7 +76,7 @@ public class JavaDeclareRecipesTranslator extends PacketTranslator<ServerDeclare
|
|||
}
|
||||
case CRAFTING_SHAPED: {
|
||||
ShapedRecipeData shapedRecipeData = (ShapedRecipeData) recipe.getData();
|
||||
ItemData output = Translators.getItemTranslator().translateToBedrock(session, shapedRecipeData.getResult());
|
||||
ItemData output = ItemTranslator.translateToBedrock(session, shapedRecipeData.getResult());
|
||||
output = ItemData.of(output.getId(), output.getDamage(), output.getCount()); //strip NBT
|
||||
ItemData[][] inputCombinations = combinations(session, shapedRecipeData.getIngredients());
|
||||
for (ItemData[] inputs : inputCombinations) {
|
||||
|
@ -103,7 +103,7 @@ public class JavaDeclareRecipesTranslator extends PacketTranslator<ServerDeclare
|
|||
}
|
||||
Ingredient ingredient = ingredients[i];
|
||||
Map<GroupedItem, List<ItemData>> groupedByIds = Arrays.stream(ingredient.getOptions())
|
||||
.map(item -> Translators.getItemTranslator().translateToBedrock(session, item))
|
||||
.map(item -> ItemTranslator.translateToBedrock(session, item))
|
||||
.collect(Collectors.groupingBy(item -> new GroupedItem(item.getId(), item.getCount(), item.getTag())));
|
||||
Set<ItemData> optionSet = new HashSet<>(groupedByIds.size());
|
||||
for (Map.Entry<GroupedItem, List<ItemData>> entry : groupedByIds.entrySet()) {
|
||||
|
@ -111,7 +111,7 @@ public class JavaDeclareRecipesTranslator extends PacketTranslator<ServerDeclare
|
|||
GroupedItem groupedItem = entry.getKey();
|
||||
int idCount = 0;
|
||||
//not optimal
|
||||
for (ItemEntry itemEntry : Toolbox.ITEM_ENTRIES.values()) {
|
||||
for (ItemEntry itemEntry : ItemRegistry.ITEM_ENTRIES.values()) {
|
||||
if (itemEntry.getBedrockId() == groupedItem.id) {
|
||||
idCount++;
|
||||
}
|
||||
|
@ -136,7 +136,7 @@ public class JavaDeclareRecipesTranslator extends PacketTranslator<ServerDeclare
|
|||
ItemData[] translatedItems = new ItemData[ingredients.length];
|
||||
for (int i = 0; i < ingredients.length; i++) {
|
||||
if (ingredients[i].getOptions().length > 0) {
|
||||
translatedItems[i] = Translators.getItemTranslator().translateToBedrock(session, ingredients[i].getOptions()[0]);
|
||||
translatedItems[i] = ItemTranslator.translateToBedrock(session, ingredients[i].getOptions()[0]);
|
||||
} else {
|
||||
translatedItems[i] = ItemData.AIR;
|
||||
}
|
||||
|
|
|
@ -0,0 +1,81 @@
|
|||
/*
|
||||
* Copyright (c) 2019-2020 GeyserMC. http://geysermc.org
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*
|
||||
* @author GeyserMC
|
||||
* @link https://github.com/GeyserMC/Geyser
|
||||
*
|
||||
*/
|
||||
|
||||
package org.geysermc.connector.network.translators.java.entity;
|
||||
|
||||
import com.github.steveice10.mc.protocol.packet.ingame.server.entity.ServerEntityAttachPacket;
|
||||
import com.nukkitx.protocol.bedrock.data.EntityData;
|
||||
import com.nukkitx.protocol.bedrock.data.EntityEventType;
|
||||
import com.nukkitx.protocol.bedrock.data.EntityFlag;
|
||||
import com.nukkitx.protocol.bedrock.packet.EntityEventPacket;
|
||||
import org.geysermc.connector.entity.Entity;
|
||||
import org.geysermc.connector.network.session.GeyserSession;
|
||||
import org.geysermc.connector.network.translators.PacketTranslator;
|
||||
import org.geysermc.connector.network.translators.Translator;
|
||||
|
||||
/**
|
||||
* Called when a leash is attached, removed or updated from an entity
|
||||
*/
|
||||
@Translator(packet = ServerEntityAttachPacket.class)
|
||||
public class JavaEntityAttachTranslator extends PacketTranslator<ServerEntityAttachPacket> {
|
||||
|
||||
@Override
|
||||
public void translate(ServerEntityAttachPacket packet, GeyserSession session) {
|
||||
|
||||
Entity holderId;
|
||||
if (packet.getEntityId() == session.getPlayerEntity().getEntityId()) {
|
||||
holderId = session.getPlayerEntity();
|
||||
} else {
|
||||
holderId = session.getEntityCache().getEntityByJavaId(packet.getEntityId());
|
||||
if (holderId == null) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
Entity attachedToId;
|
||||
if (packet.getAttachedToId() == session.getPlayerEntity().getEntityId()) {
|
||||
attachedToId = session.getPlayerEntity();
|
||||
} else {
|
||||
attachedToId = session.getEntityCache().getEntityByJavaId(packet.getAttachedToId());
|
||||
if ((attachedToId == null || packet.getAttachedToId() == 0)) {
|
||||
// Is not being leashed
|
||||
holderId.getMetadata().getFlags().setFlag(EntityFlag.LEASHED, false);
|
||||
holderId.getMetadata().put(EntityData.LEAD_HOLDER_EID, 0);
|
||||
holderId.updateBedrockMetadata(session);
|
||||
EntityEventPacket eventPacket = new EntityEventPacket();
|
||||
eventPacket.setRuntimeEntityId(holderId.getGeyserId());
|
||||
eventPacket.setType(EntityEventType.REMOVE_LEASH);
|
||||
eventPacket.setData(0);
|
||||
session.sendUpstreamPacket(eventPacket);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
holderId.getMetadata().getFlags().setFlag(EntityFlag.LEASHED, true);
|
||||
holderId.getMetadata().put(EntityData.LEAD_HOLDER_EID, attachedToId.getGeyserId());
|
||||
holderId.updateBedrockMetadata(session);
|
||||
}
|
||||
}
|
|
@ -30,10 +30,10 @@ import org.geysermc.connector.entity.LivingEntity;
|
|||
import org.geysermc.connector.network.session.GeyserSession;
|
||||
import org.geysermc.connector.network.translators.PacketTranslator;
|
||||
import org.geysermc.connector.network.translators.Translator;
|
||||
import org.geysermc.connector.network.translators.Translators;
|
||||
|
||||
import com.github.steveice10.mc.protocol.packet.ingame.server.entity.ServerEntityEquipmentPacket;
|
||||
import com.nukkitx.protocol.bedrock.data.ItemData;
|
||||
import org.geysermc.connector.network.translators.item.ItemTranslator;
|
||||
|
||||
@Translator(packet = ServerEntityEquipmentPacket.class)
|
||||
public class JavaEntityEquipmentTranslator extends PacketTranslator<ServerEntityEquipmentPacket> {
|
||||
|
@ -55,7 +55,7 @@ public class JavaEntityEquipmentTranslator extends PacketTranslator<ServerEntity
|
|||
}
|
||||
|
||||
LivingEntity livingEntity = (LivingEntity) entity;
|
||||
ItemData item = Translators.getItemTranslator().translateToBedrock(session, packet.getItem());
|
||||
ItemData item = ItemTranslator.translateToBedrock(session, packet.getItem());
|
||||
switch (packet.getSlot()) {
|
||||
case HELMET:
|
||||
livingEntity.setHelmet(item);
|
||||
|
|
|
@ -50,7 +50,7 @@ public class JavaEntityHeadLookTranslator extends PacketTranslator<ServerEntityH
|
|||
|
||||
entity.setRotation(Vector3f.from(entity.getRotation().getX(), entity.getRotation().getY(), packet.getHeadYaw()));
|
||||
|
||||
if (entity.getEntityType() != EntityType.PLAYER) {
|
||||
if (entity.getEntityType() != EntityType.PLAYER && entity.getEntityType() != EntityType.PAINTING) {
|
||||
MoveEntityAbsolutePacket moveEntityAbsolutePacket = new MoveEntityAbsolutePacket();
|
||||
moveEntityAbsolutePacket.setRuntimeEntityId(entity.getGeyserId());
|
||||
moveEntityAbsolutePacket.setPosition(entity.getPosition());
|
||||
|
|
|
@ -26,6 +26,7 @@
|
|||
package org.geysermc.connector.network.translators.java.entity;
|
||||
|
||||
import org.geysermc.connector.entity.Entity;
|
||||
import org.geysermc.connector.entity.type.EntityType;
|
||||
import org.geysermc.connector.network.session.GeyserSession;
|
||||
import org.geysermc.connector.network.translators.PacketTranslator;
|
||||
import org.geysermc.connector.network.translators.Translator;
|
||||
|
@ -42,7 +43,10 @@ public class JavaEntityPositionRotationTranslator extends PacketTranslator<Serve
|
|||
entity = session.getPlayerEntity();
|
||||
}
|
||||
if (entity == null) return;
|
||||
|
||||
if (entity.getEntityType() == EntityType.BOAT) {
|
||||
entity.moveRelative(session, packet.getMoveX(), packet.getMoveY(), packet.getMoveZ(), packet.getYaw() - 90, packet.getPitch(), packet.isOnGround());
|
||||
} else {
|
||||
entity.moveRelative(session, packet.getMoveX(), packet.getMoveY(), packet.getMoveZ(), packet.getYaw(), packet.getPitch(), packet.isOnGround());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue