Mirror von
https://github.com/GeyserMC/Geyser.git
synchronisiert 2024-12-26 16:12:46 +01:00
Merge branch 'master' of https://github.com/GeyserMC/Geyser into feature/extensions
Dieser Commit ist enthalten in:
Commit
1ebc3fd8f6
@ -1,20 +1,25 @@
|
|||||||
val paperVersion = "1.17.1-R0.1-SNAPSHOT" // Needed because we do not support Java 17 yet
|
val paperVersion = "1.17.1-R0.1-SNAPSHOT" // Needed because we do not support Java 17 yet
|
||||||
val viaVersion = "4.0.0"
|
val viaVersion = "4.0.0"
|
||||||
val adaptersVersion = "1.4-SNAPSHOT"
|
val adaptersVersion = "1.4-SNAPSHOT"
|
||||||
|
val commodoreVersion = "1.13"
|
||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
api(projects.core)
|
api(projects.core)
|
||||||
|
|
||||||
implementation("org.geysermc.geyser.adapters", "spigot-all", adaptersVersion)
|
implementation("org.geysermc.geyser.adapters", "spigot-all", adaptersVersion)
|
||||||
|
|
||||||
|
implementation("me.lucko", "commodore", commodoreVersion)
|
||||||
}
|
}
|
||||||
|
|
||||||
platformRelocate("it.unimi.dsi.fastutil")
|
platformRelocate("it.unimi.dsi.fastutil")
|
||||||
platformRelocate("com.fasterxml.jackson")
|
platformRelocate("com.fasterxml.jackson")
|
||||||
platformRelocate("net.kyori")
|
platformRelocate("net.kyori")
|
||||||
platformRelocate("org.objectweb.asm")
|
platformRelocate("org.objectweb.asm")
|
||||||
|
platformRelocate("me.lucko.commodore")
|
||||||
|
|
||||||
// These dependencies are already present on the platform
|
// These dependencies are already present on the platform
|
||||||
provided("io.papermc.paper", "paper-api", paperVersion)
|
provided("io.papermc.paper", "paper-api", paperVersion)
|
||||||
|
provided("io.papermc.paper", "paper-mojangapi", paperVersion)
|
||||||
provided("com.viaversion", "viaversion", viaVersion)
|
provided("com.viaversion", "viaversion", viaVersion)
|
||||||
|
|
||||||
application {
|
application {
|
||||||
@ -42,5 +47,8 @@ tasks.withType<com.github.jengelman.gradle.plugins.shadow.tasks.ShadowJar> {
|
|||||||
exclude(dependency("io.netty:netty-codec-dns:.*"))
|
exclude(dependency("io.netty:netty-codec-dns:.*"))
|
||||||
exclude(dependency("io.netty:netty-resolver-dns:.*"))
|
exclude(dependency("io.netty:netty-resolver-dns:.*"))
|
||||||
exclude(dependency("io.netty:netty-resolver-dns-native-macos:.*"))
|
exclude(dependency("io.netty:netty-resolver-dns-native-macos:.*"))
|
||||||
|
|
||||||
|
// Commodore includes Brigadier
|
||||||
|
exclude(dependency("com.mojang:.*"))
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -29,7 +29,9 @@ import com.viaversion.viaversion.api.Via;
|
|||||||
import com.viaversion.viaversion.api.data.MappingData;
|
import com.viaversion.viaversion.api.data.MappingData;
|
||||||
import com.viaversion.viaversion.api.protocol.ProtocolPathEntry;
|
import com.viaversion.viaversion.api.protocol.ProtocolPathEntry;
|
||||||
import com.viaversion.viaversion.api.protocol.version.ProtocolVersion;
|
import com.viaversion.viaversion.api.protocol.version.ProtocolVersion;
|
||||||
|
import me.lucko.commodore.CommodoreProvider;
|
||||||
import org.bukkit.Bukkit;
|
import org.bukkit.Bukkit;
|
||||||
|
import org.bukkit.command.PluginCommand;
|
||||||
import org.bukkit.plugin.java.JavaPlugin;
|
import org.bukkit.plugin.java.JavaPlugin;
|
||||||
import org.geysermc.common.PlatformType;
|
import org.geysermc.common.PlatformType;
|
||||||
import org.geysermc.geyser.Constants;
|
import org.geysermc.geyser.Constants;
|
||||||
@ -43,6 +45,7 @@ import org.geysermc.geyser.level.WorldManager;
|
|||||||
import org.geysermc.geyser.network.GameProtocol;
|
import org.geysermc.geyser.network.GameProtocol;
|
||||||
import org.geysermc.geyser.ping.GeyserLegacyPingPassthrough;
|
import org.geysermc.geyser.ping.GeyserLegacyPingPassthrough;
|
||||||
import org.geysermc.geyser.ping.IGeyserPingPassthrough;
|
import org.geysermc.geyser.ping.IGeyserPingPassthrough;
|
||||||
|
import org.geysermc.geyser.platform.spigot.command.GeyserBrigadierSupport;
|
||||||
import org.geysermc.geyser.platform.spigot.command.GeyserSpigotCommandExecutor;
|
import org.geysermc.geyser.platform.spigot.command.GeyserSpigotCommandExecutor;
|
||||||
import org.geysermc.geyser.platform.spigot.command.GeyserSpigotCommandManager;
|
import org.geysermc.geyser.platform.spigot.command.GeyserSpigotCommandManager;
|
||||||
import org.geysermc.geyser.platform.spigot.command.SpigotCommandSource;
|
import org.geysermc.geyser.platform.spigot.command.SpigotCommandSource;
|
||||||
@ -235,7 +238,14 @@ public class GeyserSpigotPlugin extends JavaPlugin implements GeyserBootstrap {
|
|||||||
|
|
||||||
Bukkit.getServer().getPluginManager().registerEvents(new GeyserPistonListener(geyser, this.geyserWorldManager), this);
|
Bukkit.getServer().getPluginManager().registerEvents(new GeyserPistonListener(geyser, this.geyserWorldManager), this);
|
||||||
|
|
||||||
this.getCommand("geyser").setExecutor(new GeyserSpigotCommandExecutor(geyser));
|
PluginCommand pluginCommand = this.getCommand("geyser");
|
||||||
|
pluginCommand.setExecutor(new GeyserSpigotCommandExecutor(geyser));
|
||||||
|
|
||||||
|
boolean brigadierSupported = CommodoreProvider.isSupported();
|
||||||
|
geyserLogger.debug("Brigadier supported? " + brigadierSupported);
|
||||||
|
if (brigadierSupported) {
|
||||||
|
GeyserBrigadierSupport.loadBrigadier(this, pluginCommand);
|
||||||
|
}
|
||||||
|
|
||||||
// Check to ensure the current setup can support the protocol version Geyser uses
|
// Check to ensure the current setup can support the protocol version Geyser uses
|
||||||
GeyserSpigotVersionChecker.checkForSupportedProtocol(geyserLogger, isViaVersion);
|
GeyserSpigotVersionChecker.checkForSupportedProtocol(geyserLogger, isViaVersion);
|
||||||
|
@ -0,0 +1,61 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2019-2022 GeyserMC. http://geysermc.org
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
* of this software and associated documentation files (the "Software"), to deal
|
||||||
|
* in the Software without restriction, including without limitation the rights
|
||||||
|
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
* copies of the Software, and to permit persons to whom the Software is
|
||||||
|
* furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in
|
||||||
|
* all copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
|
* THE SOFTWARE.
|
||||||
|
*
|
||||||
|
* @author GeyserMC
|
||||||
|
* @link https://github.com/GeyserMC/Geyser
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.geysermc.geyser.platform.spigot.command;
|
||||||
|
|
||||||
|
import com.mojang.brigadier.builder.LiteralArgumentBuilder;
|
||||||
|
import me.lucko.commodore.Commodore;
|
||||||
|
import me.lucko.commodore.CommodoreProvider;
|
||||||
|
import org.bukkit.Bukkit;
|
||||||
|
import org.bukkit.command.PluginCommand;
|
||||||
|
import org.geysermc.geyser.platform.spigot.GeyserSpigotPlugin;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Needs to be a separate class so pre-1.13 loads correctly.
|
||||||
|
*/
|
||||||
|
public final class GeyserBrigadierSupport {
|
||||||
|
|
||||||
|
public static void loadBrigadier(GeyserSpigotPlugin plugin, PluginCommand pluginCommand) {
|
||||||
|
// Enable command completions if supported
|
||||||
|
// This is beneficial because this is sent over the network and Bedrock can see it
|
||||||
|
Commodore commodore = CommodoreProvider.getCommodore(plugin);
|
||||||
|
LiteralArgumentBuilder<?> builder = LiteralArgumentBuilder.literal("geyser");
|
||||||
|
for (String command : plugin.getGeyserCommandManager().getCommands().keySet()) {
|
||||||
|
builder.then(LiteralArgumentBuilder.literal(command));
|
||||||
|
}
|
||||||
|
commodore.register(pluginCommand, builder);
|
||||||
|
|
||||||
|
try {
|
||||||
|
Class.forName("com.destroystokyo.paper.event.brigadier.AsyncPlayerSendCommandsEvent");
|
||||||
|
Bukkit.getServer().getPluginManager().registerEvents(new GeyserPaperCommandListener(), plugin);
|
||||||
|
plugin.getGeyserLogger().debug("Successfully registered AsyncPlayerSendCommandsEvent listener.");
|
||||||
|
} catch (ClassNotFoundException e) {
|
||||||
|
plugin.getGeyserLogger().debug("Not registering AsyncPlayerSendCommandsEvent listener.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private GeyserBrigadierSupport() {
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,87 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2019-2022 GeyserMC. http://geysermc.org
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
* of this software and associated documentation files (the "Software"), to deal
|
||||||
|
* in the Software without restriction, including without limitation the rights
|
||||||
|
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
* copies of the Software, and to permit persons to whom the Software is
|
||||||
|
* furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in
|
||||||
|
* all copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
|
* THE SOFTWARE.
|
||||||
|
*
|
||||||
|
* @author GeyserMC
|
||||||
|
* @link https://github.com/GeyserMC/Geyser
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.geysermc.geyser.platform.spigot.command;
|
||||||
|
|
||||||
|
import com.destroystokyo.paper.event.brigadier.AsyncPlayerSendCommandsEvent;
|
||||||
|
import com.mojang.brigadier.tree.CommandNode;
|
||||||
|
import org.bukkit.entity.Player;
|
||||||
|
import org.bukkit.event.EventHandler;
|
||||||
|
import org.bukkit.event.Listener;
|
||||||
|
import org.geysermc.geyser.GeyserImpl;
|
||||||
|
import org.geysermc.geyser.api.command.Command;
|
||||||
|
|
||||||
|
import java.net.InetSocketAddress;
|
||||||
|
import java.util.Iterator;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
public final class GeyserPaperCommandListener implements Listener {
|
||||||
|
|
||||||
|
@EventHandler
|
||||||
|
@SuppressWarnings("deprecation") // Used to indicate an unstable event
|
||||||
|
public void onCommandSend(AsyncPlayerSendCommandsEvent<?> event) {
|
||||||
|
// Documentation says to check (event.isAsynchronous() || !event.hasFiredAsync()), but as of Paper 1.18.2
|
||||||
|
// event.hasFiredAsync is never true
|
||||||
|
if (event.isAsynchronous()) {
|
||||||
|
CommandNode<?> geyserBrigadier = event.getCommandNode().getChild("geyser");
|
||||||
|
if (geyserBrigadier != null) {
|
||||||
|
Player player = event.getPlayer();
|
||||||
|
boolean isJavaPlayer = isProbablyJavaPlayer(player);
|
||||||
|
Map<String, Command> commands = GeyserImpl.getInstance().commandManager().getCommands();
|
||||||
|
Iterator<? extends CommandNode<?>> it = geyserBrigadier.getChildren().iterator();
|
||||||
|
|
||||||
|
while (it.hasNext()) {
|
||||||
|
CommandNode<?> subnode = it.next();
|
||||||
|
Command command = commands.get(subnode.getName());
|
||||||
|
if (command != null) {
|
||||||
|
if ((command.isBedrockOnly() && isJavaPlayer) || !player.hasPermission(command.permission())) {
|
||||||
|
// Remove this from the node as we don't have permission to use it
|
||||||
|
it.remove();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This early on, there is a rare chance that Geyser has yet to process the connection. We'll try to minimize that
|
||||||
|
* chance, though.
|
||||||
|
*/
|
||||||
|
private boolean isProbablyJavaPlayer(Player player) {
|
||||||
|
if (GeyserImpl.getInstance().connectionByUuid(player.getUniqueId()) != null) {
|
||||||
|
// For sure this is a Bedrock player
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (GeyserImpl.getInstance().getConfig().isUseDirectConnection()) {
|
||||||
|
InetSocketAddress address = player.getAddress();
|
||||||
|
if (address != null) {
|
||||||
|
return address.getPort() != 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
@ -26,6 +26,7 @@
|
|||||||
package org.geysermc.geyser.platform.spigot.command;
|
package org.geysermc.geyser.platform.spigot.command;
|
||||||
|
|
||||||
import org.bukkit.Bukkit;
|
import org.bukkit.Bukkit;
|
||||||
|
import org.bukkit.Server;
|
||||||
import org.bukkit.command.Command;
|
import org.bukkit.command.Command;
|
||||||
import org.bukkit.command.CommandMap;
|
import org.bukkit.command.CommandMap;
|
||||||
import org.geysermc.geyser.GeyserImpl;
|
import org.geysermc.geyser.GeyserImpl;
|
||||||
@ -35,16 +36,24 @@ import java.lang.reflect.Field;
|
|||||||
|
|
||||||
public class GeyserSpigotCommandManager extends GeyserCommandManager {
|
public class GeyserSpigotCommandManager extends GeyserCommandManager {
|
||||||
|
|
||||||
private static CommandMap COMMAND_MAP;
|
private static final CommandMap COMMAND_MAP;
|
||||||
|
|
||||||
static {
|
static {
|
||||||
|
CommandMap commandMap = null;
|
||||||
try {
|
try {
|
||||||
Field cmdMapField = Bukkit.getServer().getClass().getDeclaredField("commandMap");
|
// Paper-only
|
||||||
cmdMapField.setAccessible(true);
|
Server.class.getMethod("getCommandMap");
|
||||||
COMMAND_MAP = (CommandMap) cmdMapField.get(Bukkit.getServer());
|
commandMap = Bukkit.getServer().getCommandMap();
|
||||||
} catch (NoSuchFieldException | IllegalAccessException ex) {
|
} catch (NoSuchMethodException e) {
|
||||||
ex.printStackTrace();
|
try {
|
||||||
|
Field cmdMapField = Bukkit.getServer().getClass().getDeclaredField("commandMap");
|
||||||
|
cmdMapField.setAccessible(true);
|
||||||
|
commandMap = (CommandMap) cmdMapField.get(Bukkit.getServer());
|
||||||
|
} catch (NoSuchFieldException | IllegalAccessException ex) {
|
||||||
|
ex.printStackTrace();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
COMMAND_MAP = commandMap;
|
||||||
}
|
}
|
||||||
|
|
||||||
public GeyserSpigotCommandManager(GeyserImpl geyser) {
|
public GeyserSpigotCommandManager(GeyserImpl geyser) {
|
||||||
|
@ -24,7 +24,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
object Versions {
|
object Versions {
|
||||||
const val jacksonVersion = "2.12.4"
|
const val jacksonVersion = "2.13.2"
|
||||||
const val fastutilVersion = "8.5.2"
|
const val fastutilVersion = "8.5.2"
|
||||||
const val nettyVersion = "4.1.66.Final"
|
const val nettyVersion = "4.1.66.Final"
|
||||||
const val guavaVersion = "29.0-jre"
|
const val guavaVersion = "29.0-jre"
|
||||||
|
@ -12,7 +12,7 @@ dependencies {
|
|||||||
|
|
||||||
// Jackson JSON and YAML serialization
|
// Jackson JSON and YAML serialization
|
||||||
api("com.fasterxml.jackson.core", "jackson-annotations", Versions.jacksonVersion)
|
api("com.fasterxml.jackson.core", "jackson-annotations", Versions.jacksonVersion)
|
||||||
api("com.fasterxml.jackson.core", "jackson-databind", Versions.jacksonVersion)
|
api("com.fasterxml.jackson.core", "jackson-databind", Versions.jacksonVersion + ".1") // Extra .1 as databind is a slightly different version
|
||||||
api("com.fasterxml.jackson.dataformat", "jackson-dataformat-yaml", Versions.jacksonVersion)
|
api("com.fasterxml.jackson.dataformat", "jackson-dataformat-yaml", Versions.jacksonVersion)
|
||||||
api("com.google.guava", "guava", Versions.guavaVersion)
|
api("com.google.guava", "guava", Versions.guavaVersion)
|
||||||
|
|
||||||
|
@ -25,7 +25,6 @@
|
|||||||
|
|
||||||
package org.geysermc.geyser.entity.type.player;
|
package org.geysermc.geyser.entity.type.player;
|
||||||
|
|
||||||
import com.github.steveice10.mc.auth.data.GameProfile;
|
|
||||||
import com.github.steveice10.mc.protocol.data.game.entity.metadata.EntityMetadata;
|
import com.github.steveice10.mc.protocol.data.game.entity.metadata.EntityMetadata;
|
||||||
import com.github.steveice10.mc.protocol.data.game.entity.metadata.Pose;
|
import com.github.steveice10.mc.protocol.data.game.entity.metadata.Pose;
|
||||||
import com.github.steveice10.mc.protocol.data.game.entity.metadata.Position;
|
import com.github.steveice10.mc.protocol.data.game.entity.metadata.Position;
|
||||||
@ -61,15 +60,21 @@ import org.geysermc.geyser.translator.text.MessageTranslator;
|
|||||||
import javax.annotation.Nullable;
|
import javax.annotation.Nullable;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
|
import java.util.UUID;
|
||||||
import java.util.concurrent.TimeUnit;
|
import java.util.concurrent.TimeUnit;
|
||||||
|
|
||||||
@Getter @Setter
|
@Getter @Setter
|
||||||
public class PlayerEntity extends LivingEntity {
|
public class PlayerEntity extends LivingEntity {
|
||||||
public static final float SNEAKING_POSE_HEIGHT = 1.5f;
|
public static final float SNEAKING_POSE_HEIGHT = 1.5f;
|
||||||
|
|
||||||
private GameProfile profile;
|
|
||||||
private String username;
|
private String username;
|
||||||
private boolean playerList = true; // Player is in the player list
|
private boolean playerList = true; // Player is in the player list
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The textures property from the GameProfile.
|
||||||
|
*/
|
||||||
|
@Nullable
|
||||||
|
private String texturesProperty;
|
||||||
|
|
||||||
private Vector3i bedPosition;
|
private Vector3i bedPosition;
|
||||||
|
|
||||||
@ -82,11 +87,12 @@ public class PlayerEntity extends LivingEntity {
|
|||||||
*/
|
*/
|
||||||
private ParrotEntity rightParrot;
|
private ParrotEntity rightParrot;
|
||||||
|
|
||||||
public PlayerEntity(GeyserSession session, int entityId, long geyserId, GameProfile gameProfile, Vector3f position, Vector3f motion, float yaw, float pitch, float headYaw) {
|
public PlayerEntity(GeyserSession session, int entityId, long geyserId, UUID uuid, Vector3f position,
|
||||||
super(session, entityId, geyserId, gameProfile.getId(), EntityDefinitions.PLAYER, position, motion, yaw, pitch, headYaw);
|
Vector3f motion, float yaw, float pitch, float headYaw, String username, @Nullable String texturesProperty) {
|
||||||
|
super(session, entityId, geyserId, uuid, EntityDefinitions.PLAYER, position, motion, yaw, pitch, headYaw);
|
||||||
|
|
||||||
profile = gameProfile;
|
this.username = username;
|
||||||
username = gameProfile.getName();
|
this.texturesProperty = texturesProperty;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -25,7 +25,6 @@
|
|||||||
|
|
||||||
package org.geysermc.geyser.entity.type.player;
|
package org.geysermc.geyser.entity.type.player;
|
||||||
|
|
||||||
import com.github.steveice10.mc.auth.data.GameProfile;
|
|
||||||
import com.github.steveice10.mc.protocol.data.game.entity.attribute.Attribute;
|
import com.github.steveice10.mc.protocol.data.game.entity.attribute.Attribute;
|
||||||
import com.github.steveice10.mc.protocol.data.game.entity.attribute.AttributeType;
|
import com.github.steveice10.mc.protocol.data.game.entity.attribute.AttributeType;
|
||||||
import com.github.steveice10.mc.protocol.data.game.entity.metadata.Pose;
|
import com.github.steveice10.mc.protocol.data.game.entity.metadata.Pose;
|
||||||
@ -71,7 +70,7 @@ public class SessionPlayerEntity extends PlayerEntity {
|
|||||||
private int fakeTradeXp;
|
private int fakeTradeXp;
|
||||||
|
|
||||||
public SessionPlayerEntity(GeyserSession session) {
|
public SessionPlayerEntity(GeyserSession session) {
|
||||||
super(session, -1, 1, new GameProfile(UUID.randomUUID(), "unknown"), Vector3f.ZERO, Vector3f.ZERO, 0, 0, 0);
|
super(session, -1, 1, UUID.randomUUID(), Vector3f.ZERO, Vector3f.ZERO, 0, 0, 0, "unknown", null);
|
||||||
|
|
||||||
valid = true;
|
valid = true;
|
||||||
}
|
}
|
||||||
|
@ -25,7 +25,6 @@
|
|||||||
|
|
||||||
package org.geysermc.geyser.entity.type.player;
|
package org.geysermc.geyser.entity.type.player;
|
||||||
|
|
||||||
import com.github.steveice10.mc.auth.data.GameProfile;
|
|
||||||
import com.nukkitx.math.vector.Vector3f;
|
import com.nukkitx.math.vector.Vector3f;
|
||||||
import com.nukkitx.math.vector.Vector3i;
|
import com.nukkitx.math.vector.Vector3i;
|
||||||
import com.nukkitx.protocol.bedrock.data.PlayerPermission;
|
import com.nukkitx.protocol.bedrock.data.PlayerPermission;
|
||||||
@ -36,6 +35,8 @@ import com.nukkitx.protocol.bedrock.packet.AddPlayerPacket;
|
|||||||
import lombok.Getter;
|
import lombok.Getter;
|
||||||
import org.geysermc.geyser.session.GeyserSession;
|
import org.geysermc.geyser.session.GeyserSession;
|
||||||
|
|
||||||
|
import java.util.UUID;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A wrapper to handle skulls more effectively - skulls have to be treated as entities since there are no
|
* A wrapper to handle skulls more effectively - skulls have to be treated as entities since there are no
|
||||||
* custom player skulls in Bedrock.
|
* custom player skulls in Bedrock.
|
||||||
@ -48,8 +49,8 @@ public class SkullPlayerEntity extends PlayerEntity {
|
|||||||
@Getter
|
@Getter
|
||||||
private final int blockState;
|
private final int blockState;
|
||||||
|
|
||||||
public SkullPlayerEntity(GeyserSession session, long geyserId, GameProfile gameProfile, Vector3f position, float rotation, int blockState) {
|
public SkullPlayerEntity(GeyserSession session, long geyserId, Vector3f position, float rotation, int blockState, String texturesProperty) {
|
||||||
super(session, 0, geyserId, gameProfile, position, Vector3f.ZERO, rotation, 0, rotation);
|
super(session, 0, geyserId, UUID.randomUUID(), position, Vector3f.ZERO, rotation, 0, rotation, "", texturesProperty);
|
||||||
this.blockState = blockState;
|
this.blockState = blockState;
|
||||||
setPlayerList(false);
|
setPlayerList(false);
|
||||||
}
|
}
|
||||||
|
@ -391,7 +391,7 @@ public final class ClickPlan {
|
|||||||
public IntSet getAffectedSlots() {
|
public IntSet getAffectedSlots() {
|
||||||
IntSet affectedSlots = new IntOpenHashSet();
|
IntSet affectedSlots = new IntOpenHashSet();
|
||||||
for (ClickAction action : plan) {
|
for (ClickAction action : plan) {
|
||||||
if (translator.getSlotType(action.slot) == SlotType.NORMAL && action.slot != Click.OUTSIDE_SLOT) {
|
if (translator.getSlotType(action.slot) != SlotType.OUTPUT && action.slot != Click.OUTSIDE_SLOT) {
|
||||||
affectedSlots.add(action.slot);
|
affectedSlots.add(action.slot);
|
||||||
if (action.click.actionType == ContainerActionType.MOVE_TO_HOTBAR_SLOT) {
|
if (action.click.actionType == ContainerActionType.MOVE_TO_HOTBAR_SLOT) {
|
||||||
//TODO won't work if offhand is added
|
//TODO won't work if offhand is added
|
||||||
|
@ -52,7 +52,6 @@ public class StoredItemMappings {
|
|||||||
private final int goldIngot;
|
private final int goldIngot;
|
||||||
private final int ironIngot;
|
private final int ironIngot;
|
||||||
private final int lead;
|
private final int lead;
|
||||||
private final ItemMapping lodestoneCompass;
|
|
||||||
private final ItemMapping milkBucket;
|
private final ItemMapping milkBucket;
|
||||||
private final int nameTag;
|
private final int nameTag;
|
||||||
private final ItemMapping powderSnowBucket;
|
private final ItemMapping powderSnowBucket;
|
||||||
@ -80,7 +79,6 @@ public class StoredItemMappings {
|
|||||||
this.goldIngot = load(itemMappings, "gold_ingot").getJavaId();
|
this.goldIngot = load(itemMappings, "gold_ingot").getJavaId();
|
||||||
this.ironIngot = load(itemMappings, "iron_ingot").getJavaId();
|
this.ironIngot = load(itemMappings, "iron_ingot").getJavaId();
|
||||||
this.lead = load(itemMappings, "lead").getJavaId();
|
this.lead = load(itemMappings, "lead").getJavaId();
|
||||||
this.lodestoneCompass = load(itemMappings, "lodestone_compass");
|
|
||||||
this.milkBucket = load(itemMappings, "milk_bucket");
|
this.milkBucket = load(itemMappings, "milk_bucket");
|
||||||
this.nameTag = load(itemMappings, "name_tag").getJavaId();
|
this.nameTag = load(itemMappings, "name_tag").getJavaId();
|
||||||
this.powderSnowBucket = load(itemMappings, "powder_snow_bucket");
|
this.powderSnowBucket = load(itemMappings, "powder_snow_bucket");
|
||||||
|
@ -1,92 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (c) 2019-2022 GeyserMC. http://geysermc.org
|
|
||||||
*
|
|
||||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
||||||
* of this software and associated documentation files (the "Software"), to deal
|
|
||||||
* in the Software without restriction, including without limitation the rights
|
|
||||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
||||||
* copies of the Software, and to permit persons to whom the Software is
|
|
||||||
* furnished to do so, subject to the following conditions:
|
|
||||||
*
|
|
||||||
* The above copyright notice and this permission notice shall be included in
|
|
||||||
* all copies or substantial portions of the Software.
|
|
||||||
*
|
|
||||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
||||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
||||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
||||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
||||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
||||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
|
||||||
* THE SOFTWARE.
|
|
||||||
*
|
|
||||||
* @author GeyserMC
|
|
||||||
* @link https://github.com/GeyserMC/Geyser
|
|
||||||
*/
|
|
||||||
|
|
||||||
package org.geysermc.geyser.level.chunk;
|
|
||||||
|
|
||||||
import com.nukkitx.network.util.Preconditions;
|
|
||||||
|
|
||||||
public class NibbleArray implements Cloneable {
|
|
||||||
|
|
||||||
private final byte[] data;
|
|
||||||
|
|
||||||
public NibbleArray(int length) {
|
|
||||||
data = new byte[length / 2];
|
|
||||||
}
|
|
||||||
|
|
||||||
public NibbleArray(byte[] array) {
|
|
||||||
data = array;
|
|
||||||
}
|
|
||||||
|
|
||||||
public byte get(int index) {
|
|
||||||
Preconditions.checkElementIndex(index, data.length * 2);
|
|
||||||
byte val = data[index / 2];
|
|
||||||
if ((index & 1) == 0) {
|
|
||||||
return (byte) (val & 0x0f);
|
|
||||||
} else {
|
|
||||||
return (byte) ((val & 0xf0) >>> 4);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void set(int index, byte value) {
|
|
||||||
Preconditions.checkArgument(value >= 0 && value < 16, "Nibbles must have a value between 0 and 15.");
|
|
||||||
Preconditions.checkElementIndex(index, data.length * 2);
|
|
||||||
value &= 0xf;
|
|
||||||
int half = index / 2;
|
|
||||||
byte previous = data[half];
|
|
||||||
if ((index & 1) == 0) {
|
|
||||||
data[half] = (byte) (previous & 0xf0 | value);
|
|
||||||
} else {
|
|
||||||
data[half] = (byte) (previous & 0x0f | value << 4);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void fill(byte value) {
|
|
||||||
Preconditions.checkArgument(value >= 0 && value < 16, "Nibbles must have a value between 0 and 15.");
|
|
||||||
value &= 0xf;
|
|
||||||
for (int i = 0; i < data.length; i++) {
|
|
||||||
data[i] = (byte) ((value << 4) | value);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void copyFrom(byte[] bytes) {
|
|
||||||
Preconditions.checkNotNull(bytes, "bytes");
|
|
||||||
Preconditions.checkArgument(bytes.length == data.length, "length of provided byte array is %s but expected %s", bytes.length,
|
|
||||||
data.length);
|
|
||||||
System.arraycopy(bytes, 0, data, 0, data.length);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void copyFrom(NibbleArray array) {
|
|
||||||
Preconditions.checkNotNull(array, "array");
|
|
||||||
copyFrom(array.data);
|
|
||||||
}
|
|
||||||
|
|
||||||
public byte[] getData() {
|
|
||||||
return data;
|
|
||||||
}
|
|
||||||
|
|
||||||
public NibbleArray copy() {
|
|
||||||
return new NibbleArray(getData().clone());
|
|
||||||
}
|
|
||||||
}
|
|
@ -128,7 +128,7 @@ public class ItemRegistryPopulator {
|
|||||||
IntList spawnEggs = new IntArrayList();
|
IntList spawnEggs = new IntArrayList();
|
||||||
List<ItemData> carpets = new ObjectArrayList<>();
|
List<ItemData> carpets = new ObjectArrayList<>();
|
||||||
|
|
||||||
Int2ObjectMap<ItemMapping> mappings = new Int2ObjectOpenHashMap<>();
|
List<ItemMapping> mappings = new ObjectArrayList<>();
|
||||||
// Temporary mapping to create stored items
|
// Temporary mapping to create stored items
|
||||||
Map<String, ItemMapping> identifierToMapping = new Object2ObjectOpenHashMap<>();
|
Map<String, ItemMapping> identifierToMapping = new Object2ObjectOpenHashMap<>();
|
||||||
|
|
||||||
@ -166,6 +166,9 @@ public class ItemRegistryPopulator {
|
|||||||
if (identifier.equals("minecraft:debug_stick")) {
|
if (identifier.equals("minecraft:debug_stick")) {
|
||||||
// Just shows an empty texture; either way it doesn't exist in the creative menu on Java
|
// Just shows an empty texture; either way it doesn't exist in the creative menu on Java
|
||||||
continue;
|
continue;
|
||||||
|
} else if (identifier.equals("minecraft:empty_map") && damage == 2) {
|
||||||
|
// Bedrock-only as its own item
|
||||||
|
continue;
|
||||||
}
|
}
|
||||||
StartGamePacket.ItemEntry entry = entries.get(identifier);
|
StartGamePacket.ItemEntry entry = entries.get(identifier);
|
||||||
int id = -1;
|
int id = -1;
|
||||||
@ -240,6 +243,8 @@ public class ItemRegistryPopulator {
|
|||||||
if (usingFurnaceMinecart && javaIdentifier.equals("minecraft:furnace_minecart")) {
|
if (usingFurnaceMinecart && javaIdentifier.equals("minecraft:furnace_minecart")) {
|
||||||
javaFurnaceMinecartId = itemIndex;
|
javaFurnaceMinecartId = itemIndex;
|
||||||
itemIndex++;
|
itemIndex++;
|
||||||
|
// Will be added later
|
||||||
|
mappings.add(null);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -416,7 +421,7 @@ public class ItemRegistryPopulator {
|
|||||||
spawnEggs.add(mapping.getBedrockId());
|
spawnEggs.add(mapping.getBedrockId());
|
||||||
}
|
}
|
||||||
|
|
||||||
mappings.put(itemIndex, mapping);
|
mappings.add(mapping);
|
||||||
identifierToMapping.put(javaIdentifier, mapping);
|
identifierToMapping.put(javaIdentifier, mapping);
|
||||||
|
|
||||||
itemNames.add(javaIdentifier);
|
itemNames.add(javaIdentifier);
|
||||||
@ -437,16 +442,14 @@ public class ItemRegistryPopulator {
|
|||||||
|
|
||||||
// Add the lodestone compass since it doesn't exist on java but we need it for item conversion
|
// Add the lodestone compass since it doesn't exist on java but we need it for item conversion
|
||||||
ItemMapping lodestoneEntry = ItemMapping.builder()
|
ItemMapping lodestoneEntry = ItemMapping.builder()
|
||||||
.javaIdentifier("minecraft:lodestone_compass")
|
.javaIdentifier("")
|
||||||
.bedrockIdentifier("minecraft:lodestone_compass")
|
.bedrockIdentifier("minecraft:lodestone_compass")
|
||||||
.javaId(itemIndex)
|
.javaId(-1)
|
||||||
.bedrockId(lodestoneCompassId)
|
.bedrockId(lodestoneCompassId)
|
||||||
.bedrockData(0)
|
.bedrockData(0)
|
||||||
.bedrockBlockId(-1)
|
.bedrockBlockId(-1)
|
||||||
.stackSize(1)
|
.stackSize(1)
|
||||||
.build();
|
.build();
|
||||||
mappings.put(itemIndex, lodestoneEntry);
|
|
||||||
identifierToMapping.put(lodestoneEntry.getJavaIdentifier(), lodestoneEntry);
|
|
||||||
|
|
||||||
ComponentItemData furnaceMinecartData = null;
|
ComponentItemData furnaceMinecartData = null;
|
||||||
if (usingFurnaceMinecart) {
|
if (usingFurnaceMinecart) {
|
||||||
@ -455,7 +458,7 @@ public class ItemRegistryPopulator {
|
|||||||
|
|
||||||
entries.put("geysermc:furnace_minecart", new StartGamePacket.ItemEntry("geysermc:furnace_minecart", (short) furnaceMinecartId, true));
|
entries.put("geysermc:furnace_minecart", new StartGamePacket.ItemEntry("geysermc:furnace_minecart", (short) furnaceMinecartId, true));
|
||||||
|
|
||||||
mappings.put(javaFurnaceMinecartId, ItemMapping.builder()
|
mappings.set(javaFurnaceMinecartId, ItemMapping.builder()
|
||||||
.javaIdentifier("minecraft:furnace_minecart")
|
.javaIdentifier("minecraft:furnace_minecart")
|
||||||
.bedrockIdentifier("geysermc:furnace_minecart")
|
.bedrockIdentifier("geysermc:furnace_minecart")
|
||||||
.javaId(javaFurnaceMinecartId)
|
.javaId(javaFurnaceMinecartId)
|
||||||
@ -506,9 +509,9 @@ public class ItemRegistryPopulator {
|
|||||||
}
|
}
|
||||||
|
|
||||||
ItemMappings itemMappings = ItemMappings.builder()
|
ItemMappings itemMappings = ItemMappings.builder()
|
||||||
.items(mappings)
|
.items(mappings.toArray(new ItemMapping[0]))
|
||||||
.creativeItems(creativeItems.toArray(new ItemData[0]))
|
.creativeItems(creativeItems.toArray(new ItemData[0]))
|
||||||
.itemEntries(new ArrayList<>(entries.values()))
|
.itemEntries(List.copyOf(entries.values()))
|
||||||
.itemNames(itemNames.toArray(new String[0]))
|
.itemNames(itemNames.toArray(new String[0]))
|
||||||
.storedItems(new StoredItemMappings(identifierToMapping))
|
.storedItems(new StoredItemMappings(identifierToMapping))
|
||||||
.javaOnlyItems(javaOnlyItems)
|
.javaOnlyItems(javaOnlyItems)
|
||||||
@ -517,6 +520,7 @@ public class ItemRegistryPopulator {
|
|||||||
.spawnEggIds(spawnEggs)
|
.spawnEggIds(spawnEggs)
|
||||||
.carpets(carpets)
|
.carpets(carpets)
|
||||||
.furnaceMinecartData(furnaceMinecartData)
|
.furnaceMinecartData(furnaceMinecartData)
|
||||||
|
.lodestoneCompass(lodestoneEntry)
|
||||||
.build();
|
.build();
|
||||||
|
|
||||||
Registries.ITEMS.register(palette.getValue().protocolVersion(), itemMappings);
|
Registries.ITEMS.register(palette.getValue().protocolVersion(), itemMappings);
|
||||||
|
@ -29,13 +29,13 @@ import com.github.steveice10.mc.protocol.data.game.entity.metadata.ItemStack;
|
|||||||
import com.nukkitx.protocol.bedrock.data.inventory.ComponentItemData;
|
import com.nukkitx.protocol.bedrock.data.inventory.ComponentItemData;
|
||||||
import com.nukkitx.protocol.bedrock.data.inventory.ItemData;
|
import com.nukkitx.protocol.bedrock.data.inventory.ItemData;
|
||||||
import com.nukkitx.protocol.bedrock.packet.StartGamePacket;
|
import com.nukkitx.protocol.bedrock.packet.StartGamePacket;
|
||||||
import it.unimi.dsi.fastutil.ints.Int2ObjectMap;
|
|
||||||
import it.unimi.dsi.fastutil.ints.IntList;
|
import it.unimi.dsi.fastutil.ints.IntList;
|
||||||
import lombok.Builder;
|
import lombok.Builder;
|
||||||
import lombok.Value;
|
import lombok.Value;
|
||||||
import org.geysermc.geyser.GeyserImpl;
|
import org.geysermc.geyser.GeyserImpl;
|
||||||
import org.geysermc.geyser.inventory.item.StoredItemMappings;
|
import org.geysermc.geyser.inventory.item.StoredItemMappings;
|
||||||
|
|
||||||
|
import javax.annotation.Nonnull;
|
||||||
import javax.annotation.Nullable;
|
import javax.annotation.Nullable;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
@ -48,7 +48,12 @@ public class ItemMappings {
|
|||||||
|
|
||||||
Map<String, ItemMapping> cachedJavaMappings = new WeakHashMap<>();
|
Map<String, ItemMapping> cachedJavaMappings = new WeakHashMap<>();
|
||||||
|
|
||||||
Int2ObjectMap<ItemMapping> items;
|
ItemMapping[] items;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A unique exception as this is an item in Bedrock, but not in Java.
|
||||||
|
*/
|
||||||
|
ItemMapping lodestoneCompass;
|
||||||
|
|
||||||
ItemData[] creativeItems;
|
ItemData[] creativeItems;
|
||||||
List<StartGamePacket.ItemEntry> itemEntries;
|
List<StartGamePacket.ItemEntry> itemEntries;
|
||||||
@ -70,6 +75,7 @@ public class ItemMappings {
|
|||||||
* @param itemStack the itemstack
|
* @param itemStack the itemstack
|
||||||
* @return an item entry from the given java edition identifier
|
* @return an item entry from the given java edition identifier
|
||||||
*/
|
*/
|
||||||
|
@Nonnull
|
||||||
public ItemMapping getMapping(ItemStack itemStack) {
|
public ItemMapping getMapping(ItemStack itemStack) {
|
||||||
return this.getMapping(itemStack.getId());
|
return this.getMapping(itemStack.getId());
|
||||||
}
|
}
|
||||||
@ -81,8 +87,9 @@ public class ItemMappings {
|
|||||||
* @param javaId the id
|
* @param javaId the id
|
||||||
* @return an item entry from the given java edition identifier
|
* @return an item entry from the given java edition identifier
|
||||||
*/
|
*/
|
||||||
|
@Nonnull
|
||||||
public ItemMapping getMapping(int javaId) {
|
public ItemMapping getMapping(int javaId) {
|
||||||
return this.items.get(javaId);
|
return javaId >= 0 && javaId < this.items.length ? this.items[javaId] : ItemMapping.AIR;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -94,7 +101,7 @@ public class ItemMappings {
|
|||||||
*/
|
*/
|
||||||
public ItemMapping getMapping(String javaIdentifier) {
|
public ItemMapping getMapping(String javaIdentifier) {
|
||||||
return this.cachedJavaMappings.computeIfAbsent(javaIdentifier, key -> {
|
return this.cachedJavaMappings.computeIfAbsent(javaIdentifier, key -> {
|
||||||
for (ItemMapping mapping : this.items.values()) {
|
for (ItemMapping mapping : this.items) {
|
||||||
if (mapping.getJavaIdentifier().equals(key)) {
|
if (mapping.getJavaIdentifier().equals(key)) {
|
||||||
return mapping;
|
return mapping;
|
||||||
}
|
}
|
||||||
@ -110,11 +117,18 @@ public class ItemMappings {
|
|||||||
* @return an item entry from the given item data
|
* @return an item entry from the given item data
|
||||||
*/
|
*/
|
||||||
public ItemMapping getMapping(ItemData data) {
|
public ItemMapping getMapping(ItemData data) {
|
||||||
|
int id = data.getId();
|
||||||
|
if (id == 0) {
|
||||||
|
return ItemMapping.AIR;
|
||||||
|
} else if (id == lodestoneCompass.getBedrockId()) {
|
||||||
|
return lodestoneCompass;
|
||||||
|
}
|
||||||
|
|
||||||
boolean isBlock = data.getBlockRuntimeId() != 0;
|
boolean isBlock = data.getBlockRuntimeId() != 0;
|
||||||
boolean hasDamage = data.getDamage() != 0;
|
boolean hasDamage = data.getDamage() != 0;
|
||||||
|
|
||||||
for (ItemMapping mapping : this.items.values()) {
|
for (ItemMapping mapping : this.items) {
|
||||||
if (mapping.getBedrockId() == data.getId()) {
|
if (mapping.getBedrockId() == id) {
|
||||||
if (isBlock && !hasDamage) { // Pre-1.16.220 will not use block runtime IDs at all, so we shouldn't check either
|
if (isBlock && !hasDamage) { // Pre-1.16.220 will not use block runtime IDs at all, so we shouldn't check either
|
||||||
if (data.getBlockRuntimeId() != mapping.getBedrockBlockId()) {
|
if (data.getBlockRuntimeId() != mapping.getBedrockBlockId()) {
|
||||||
continue;
|
continue;
|
||||||
@ -135,7 +149,7 @@ public class ItemMappings {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// This will hide the message when the player clicks with an empty hand
|
// This will hide the message when the player clicks with an empty hand
|
||||||
if (data.getId() != 0 && data.getDamage() != 0) {
|
if (id != 0 && data.getDamage() != 0) {
|
||||||
GeyserImpl.getInstance().getLogger().debug("Missing mapping for bedrock item " + data.getId() + ":" + data.getDamage());
|
GeyserImpl.getInstance().getLogger().debug("Missing mapping for bedrock item " + data.getId() + ":" + data.getDamage());
|
||||||
}
|
}
|
||||||
return ItemMapping.AIR;
|
return ItemMapping.AIR;
|
||||||
|
@ -26,24 +26,36 @@
|
|||||||
package org.geysermc.geyser.session.cache;
|
package org.geysermc.geyser.session.cache;
|
||||||
|
|
||||||
import com.github.steveice10.mc.protocol.data.game.setting.Difficulty;
|
import com.github.steveice10.mc.protocol.data.game.setting.Difficulty;
|
||||||
|
import com.nukkitx.protocol.bedrock.packet.SetTitlePacket;
|
||||||
import lombok.Getter;
|
import lombok.Getter;
|
||||||
import lombok.Setter;
|
import lombok.Setter;
|
||||||
import org.geysermc.geyser.session.GeyserSession;
|
|
||||||
import org.geysermc.geyser.scoreboard.Scoreboard;
|
import org.geysermc.geyser.scoreboard.Scoreboard;
|
||||||
import org.geysermc.geyser.scoreboard.ScoreboardUpdater.ScoreboardSession;
|
import org.geysermc.geyser.scoreboard.ScoreboardUpdater.ScoreboardSession;
|
||||||
|
import org.geysermc.geyser.session.GeyserSession;
|
||||||
|
|
||||||
@Getter
|
public final class WorldCache {
|
||||||
public class WorldCache {
|
|
||||||
private final GeyserSession session;
|
private final GeyserSession session;
|
||||||
|
@Getter
|
||||||
private final ScoreboardSession scoreboardSession;
|
private final ScoreboardSession scoreboardSession;
|
||||||
|
@Getter
|
||||||
private Scoreboard scoreboard;
|
private Scoreboard scoreboard;
|
||||||
|
@Getter
|
||||||
@Setter
|
@Setter
|
||||||
private Difficulty difficulty = Difficulty.EASY;
|
private Difficulty difficulty = Difficulty.EASY;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Whether our cooldown changed the title time, and the true title times need to be re-sent.
|
||||||
|
*/
|
||||||
|
private boolean titleTimesNeedReset = false;
|
||||||
|
private int trueTitleFadeInTime;
|
||||||
|
private int trueTitleStayTime;
|
||||||
|
private int trueTitleFadeOutTime;
|
||||||
|
|
||||||
public WorldCache(GeyserSession session) {
|
public WorldCache(GeyserSession session) {
|
||||||
this.session = session;
|
this.session = session;
|
||||||
this.scoreboard = new Scoreboard(session);
|
this.scoreboard = new Scoreboard(session);
|
||||||
scoreboardSession = new ScoreboardSession(session);
|
scoreboardSession = new ScoreboardSession(session);
|
||||||
|
resetTitleTimes(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void removeScoreboard() {
|
public void removeScoreboard() {
|
||||||
@ -58,4 +70,55 @@ public class WorldCache {
|
|||||||
int pps = scoreboardSession.getPacketsPerSecond();
|
int pps = scoreboardSession.getPacketsPerSecond();
|
||||||
return Math.max(pps, pendingPps);
|
return Math.max(pps, pendingPps);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void markTitleTimesAsIncorrect() {
|
||||||
|
titleTimesNeedReset = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Store the true active title times.
|
||||||
|
*/
|
||||||
|
public void setTitleTimes(int fadeInTime, int stayTime, int fadeOutTime) {
|
||||||
|
trueTitleFadeInTime = fadeInTime;
|
||||||
|
trueTitleStayTime = stayTime;
|
||||||
|
trueTitleFadeOutTime = fadeOutTime;
|
||||||
|
// The translator will sync this for us
|
||||||
|
titleTimesNeedReset = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* If needed, ensure that the Bedrock client will use the correct timings for titles.
|
||||||
|
*/
|
||||||
|
public void synchronizeCorrectTitleTimes() {
|
||||||
|
if (titleTimesNeedReset) {
|
||||||
|
forceSyncCorrectTitleTimes();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void forceSyncCorrectTitleTimes() {
|
||||||
|
SetTitlePacket titlePacket = new SetTitlePacket();
|
||||||
|
titlePacket.setType(SetTitlePacket.Type.TIMES);
|
||||||
|
titlePacket.setText("");
|
||||||
|
titlePacket.setFadeInTime(trueTitleFadeInTime);
|
||||||
|
titlePacket.setStayTime(trueTitleStayTime);
|
||||||
|
titlePacket.setFadeOutTime(trueTitleFadeOutTime);
|
||||||
|
titlePacket.setPlatformOnlineId("");
|
||||||
|
titlePacket.setXuid("");
|
||||||
|
|
||||||
|
session.sendUpstreamPacket(titlePacket);
|
||||||
|
titleTimesNeedReset = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reset the true active title times to the (Java Edition 1.18.2) defaults.
|
||||||
|
*/
|
||||||
|
public void resetTitleTimes(boolean clientSync) {
|
||||||
|
trueTitleFadeInTime = 10;
|
||||||
|
trueTitleStayTime = 70;
|
||||||
|
trueTitleFadeOutTime = 20;
|
||||||
|
|
||||||
|
if (clientSync) {
|
||||||
|
forceSyncCorrectTitleTimes();
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
@ -25,7 +25,6 @@
|
|||||||
|
|
||||||
package org.geysermc.geyser.skin;
|
package org.geysermc.geyser.skin;
|
||||||
|
|
||||||
import com.github.steveice10.mc.auth.data.GameProfile;
|
|
||||||
import com.github.steveice10.opennbt.tag.builtin.CompoundTag;
|
import com.github.steveice10.opennbt.tag.builtin.CompoundTag;
|
||||||
import com.google.common.cache.CacheBuilder;
|
import com.google.common.cache.CacheBuilder;
|
||||||
import com.google.common.cache.CacheLoader;
|
import com.google.common.cache.CacheLoader;
|
||||||
@ -106,7 +105,7 @@ public class FakeHeadProvider {
|
|||||||
|
|
||||||
session.getPlayerWithCustomHeads().add(entity.getUuid());
|
session.getPlayerWithCustomHeads().add(entity.getUuid());
|
||||||
|
|
||||||
GameProfile.Property texturesProperty = entity.getProfile().getProperty("textures");
|
String texturesProperty = entity.getTexturesProperty();
|
||||||
|
|
||||||
SkinProvider.EXECUTOR_SERVICE.execute(() -> {
|
SkinProvider.EXECUTOR_SERVICE.execute(() -> {
|
||||||
try {
|
try {
|
||||||
@ -182,7 +181,7 @@ public class FakeHeadProvider {
|
|||||||
@Getter
|
@Getter
|
||||||
@Setter
|
@Setter
|
||||||
private static class FakeHeadEntry {
|
private static class FakeHeadEntry {
|
||||||
private final GameProfile.Property texturesProperty;
|
private final String texturesProperty;
|
||||||
private final String fakeHeadSkinUrl;
|
private final String fakeHeadSkinUrl;
|
||||||
private PlayerEntity entity;
|
private PlayerEntity entity;
|
||||||
|
|
||||||
@ -192,18 +191,7 @@ public class FakeHeadProvider {
|
|||||||
if (this == o) return true;
|
if (this == o) return true;
|
||||||
if (o == null || getClass() != o.getClass()) return false;
|
if (o == null || getClass() != o.getClass()) return false;
|
||||||
FakeHeadEntry that = (FakeHeadEntry) o;
|
FakeHeadEntry that = (FakeHeadEntry) o;
|
||||||
return equals(texturesProperty, that.texturesProperty) && Objects.equals(fakeHeadSkinUrl, that.fakeHeadSkinUrl);
|
return Objects.equals(texturesProperty, that.texturesProperty) && Objects.equals(fakeHeadSkinUrl, that.fakeHeadSkinUrl);
|
||||||
}
|
|
||||||
|
|
||||||
private boolean equals(GameProfile.Property a, GameProfile.Property b) {
|
|
||||||
//TODO actually fix this in MCAuthLib
|
|
||||||
if (a == b) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
if (a == null || b == null) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
return Objects.equals(a.getName(), b.getName()) && Objects.equals(a.getValue(), b.getValue()) && Objects.equals(a.getSignature(), b.getSignature());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -26,7 +26,6 @@
|
|||||||
package org.geysermc.geyser.skin;
|
package org.geysermc.geyser.skin;
|
||||||
|
|
||||||
import com.fasterxml.jackson.databind.JsonNode;
|
import com.fasterxml.jackson.databind.JsonNode;
|
||||||
import com.github.steveice10.mc.auth.data.GameProfile;
|
|
||||||
import com.github.steveice10.opennbt.tag.builtin.CompoundTag;
|
import com.github.steveice10.opennbt.tag.builtin.CompoundTag;
|
||||||
import com.github.steveice10.opennbt.tag.builtin.ListTag;
|
import com.github.steveice10.opennbt.tag.builtin.ListTag;
|
||||||
import com.github.steveice10.opennbt.tag.builtin.StringTag;
|
import com.github.steveice10.opennbt.tag.builtin.StringTag;
|
||||||
@ -54,7 +53,7 @@ public class SkinManager {
|
|||||||
* Builds a Bedrock player list entry from our existing, cached Bedrock skin information
|
* Builds a Bedrock player list entry from our existing, cached Bedrock skin information
|
||||||
*/
|
*/
|
||||||
public static PlayerListPacket.Entry buildCachedEntry(GeyserSession session, PlayerEntity playerEntity) {
|
public static PlayerListPacket.Entry buildCachedEntry(GeyserSession session, PlayerEntity playerEntity) {
|
||||||
GameProfileData data = GameProfileData.from(playerEntity.getProfile());
|
GameProfileData data = GameProfileData.from(playerEntity);
|
||||||
SkinProvider.Cape cape = SkinProvider.getCachedCape(data.capeUrl());
|
SkinProvider.Cape cape = SkinProvider.getCachedCape(data.capeUrl());
|
||||||
SkinProvider.SkinGeometry geometry = SkinProvider.SkinGeometry.getLegacy(data.isAlex());
|
SkinProvider.SkinGeometry geometry = SkinProvider.SkinGeometry.getLegacy(data.isAlex());
|
||||||
|
|
||||||
@ -65,8 +64,8 @@ public class SkinManager {
|
|||||||
|
|
||||||
return buildEntryManually(
|
return buildEntryManually(
|
||||||
session,
|
session,
|
||||||
playerEntity.getProfile().getId(),
|
playerEntity.getUuid(),
|
||||||
playerEntity.getProfile().getName(),
|
playerEntity.getUsername(),
|
||||||
playerEntity.getGeyserId(),
|
playerEntity.getGeyserId(),
|
||||||
skin.getTextureUrl(),
|
skin.getTextureUrl(),
|
||||||
skin.getSkinData(),
|
skin.getSkinData(),
|
||||||
@ -227,31 +226,31 @@ public class SkinManager {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Generate the GameProfileData from the given GameProfile
|
* Generate the GameProfileData from the given player entity
|
||||||
*
|
*
|
||||||
* @param profile GameProfile to build the GameProfileData from
|
* @param entity entity to build the GameProfileData from
|
||||||
* @return The built GameProfileData
|
* @return The built GameProfileData
|
||||||
*/
|
*/
|
||||||
public static GameProfileData from(GameProfile profile) {
|
public static GameProfileData from(PlayerEntity entity) {
|
||||||
try {
|
try {
|
||||||
GameProfile.Property skinProperty = profile.getProperty("textures");
|
String texturesProperty = entity.getTexturesProperty();
|
||||||
|
|
||||||
if (skinProperty == null) {
|
if (texturesProperty == null) {
|
||||||
// Likely offline mode
|
// Likely offline mode
|
||||||
return loadBedrockOrOfflineSkin(profile);
|
return loadBedrockOrOfflineSkin(entity);
|
||||||
}
|
}
|
||||||
GameProfileData data = loadFromJson(skinProperty.getValue());
|
GameProfileData data = loadFromJson(texturesProperty);
|
||||||
if (data != null) {
|
if (data != null) {
|
||||||
return data;
|
return data;
|
||||||
} else {
|
} else {
|
||||||
return loadBedrockOrOfflineSkin(profile);
|
return loadBedrockOrOfflineSkin(entity);
|
||||||
}
|
}
|
||||||
} catch (IOException exception) {
|
} catch (IOException exception) {
|
||||||
GeyserImpl.getInstance().getLogger().debug("Something went wrong while processing skin for " + profile.getName());
|
GeyserImpl.getInstance().getLogger().debug("Something went wrong while processing skin for " + entity.getUsername());
|
||||||
if (GeyserImpl.getInstance().getConfig().isDebugMode()) {
|
if (GeyserImpl.getInstance().getConfig().isDebugMode()) {
|
||||||
exception.printStackTrace();
|
exception.printStackTrace();
|
||||||
}
|
}
|
||||||
return loadBedrockOrOfflineSkin(profile);
|
return loadBedrockOrOfflineSkin(entity);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -280,14 +279,15 @@ public class SkinManager {
|
|||||||
* @return default skin with default cape when texture data is invalid, or the Bedrock player's skin if this
|
* @return default skin with default cape when texture data is invalid, or the Bedrock player's skin if this
|
||||||
* is a Bedrock player.
|
* is a Bedrock player.
|
||||||
*/
|
*/
|
||||||
private static GameProfileData loadBedrockOrOfflineSkin(GameProfile profile) {
|
private static GameProfileData loadBedrockOrOfflineSkin(PlayerEntity entity) {
|
||||||
// Fallback to the offline mode of working it out
|
// Fallback to the offline mode of working it out
|
||||||
boolean isAlex = (Math.abs(profile.getId().hashCode() % 2) == 1);
|
UUID uuid = entity.getUuid();
|
||||||
|
boolean isAlex = (Math.abs(uuid.hashCode() % 2) == 1);
|
||||||
|
|
||||||
String skinUrl = isAlex ? SkinProvider.EMPTY_SKIN_ALEX.getTextureUrl() : SkinProvider.EMPTY_SKIN.getTextureUrl();
|
String skinUrl = isAlex ? SkinProvider.EMPTY_SKIN_ALEX.getTextureUrl() : SkinProvider.EMPTY_SKIN.getTextureUrl();
|
||||||
String capeUrl = SkinProvider.EMPTY_CAPE.getTextureUrl();
|
String capeUrl = SkinProvider.EMPTY_CAPE.getTextureUrl();
|
||||||
if (("steve".equals(skinUrl) || "alex".equals(skinUrl)) && GeyserImpl.getInstance().getConfig().getRemote().getAuthType() != AuthType.ONLINE) {
|
if (("steve".equals(skinUrl) || "alex".equals(skinUrl)) && GeyserImpl.getInstance().getConfig().getRemote().getAuthType() != AuthType.ONLINE) {
|
||||||
GeyserSession session = GeyserImpl.getInstance().connectionByUuid(profile.getId());
|
GeyserSession session = GeyserImpl.getInstance().connectionByUuid(uuid);
|
||||||
|
|
||||||
if (session != null) {
|
if (session != null) {
|
||||||
skinUrl = session.getClientData().getSkinId();
|
skinUrl = session.getClientData().getSkinId();
|
||||||
|
@ -27,7 +27,6 @@ package org.geysermc.geyser.skin;
|
|||||||
|
|
||||||
import com.fasterxml.jackson.databind.JsonNode;
|
import com.fasterxml.jackson.databind.JsonNode;
|
||||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||||
import com.github.steveice10.mc.auth.data.GameProfile;
|
|
||||||
import com.github.steveice10.opennbt.tag.builtin.CompoundTag;
|
import com.github.steveice10.opennbt.tag.builtin.CompoundTag;
|
||||||
import com.github.steveice10.opennbt.tag.builtin.IntArrayTag;
|
import com.github.steveice10.opennbt.tag.builtin.IntArrayTag;
|
||||||
import com.github.steveice10.opennbt.tag.builtin.Tag;
|
import com.github.steveice10.opennbt.tag.builtin.Tag;
|
||||||
@ -53,7 +52,6 @@ import java.io.IOException;
|
|||||||
import java.net.HttpURLConnection;
|
import java.net.HttpURLConnection;
|
||||||
import java.net.URL;
|
import java.net.URL;
|
||||||
import java.nio.charset.StandardCharsets;
|
import java.nio.charset.StandardCharsets;
|
||||||
import java.util.List;
|
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
import java.util.concurrent.*;
|
import java.util.concurrent.*;
|
||||||
import java.util.function.Predicate;
|
import java.util.function.Predicate;
|
||||||
@ -157,7 +155,7 @@ public class SkinProvider {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public static CompletableFuture<SkinProvider.SkinData> requestSkinData(PlayerEntity entity) {
|
public static CompletableFuture<SkinProvider.SkinData> requestSkinData(PlayerEntity entity) {
|
||||||
SkinManager.GameProfileData data = SkinManager.GameProfileData.from(entity.getProfile());
|
SkinManager.GameProfileData data = SkinManager.GameProfileData.from(entity);
|
||||||
|
|
||||||
return requestSkinAndCape(entity.getUuid(), data.skinUrl(), data.capeUrl())
|
return requestSkinAndCape(entity.getUuid(), data.skinUrl(), data.capeUrl())
|
||||||
.thenApplyAsync(skinAndCape -> {
|
.thenApplyAsync(skinAndCape -> {
|
||||||
@ -546,12 +544,11 @@ public class SkinProvider {
|
|||||||
* @param skullOwner the CompoundTag of the skull with no textures
|
* @param skullOwner the CompoundTag of the skull with no textures
|
||||||
* @return a completable GameProfile with textures included
|
* @return a completable GameProfile with textures included
|
||||||
*/
|
*/
|
||||||
public static CompletableFuture<GameProfile> requestTexturesFromUsername(CompoundTag skullOwner) {
|
public static CompletableFuture<String> requestTexturesFromUsername(CompoundTag skullOwner) {
|
||||||
return CompletableFuture.supplyAsync(() -> {
|
return CompletableFuture.supplyAsync(() -> {
|
||||||
Tag uuidTag = skullOwner.get("Id");
|
Tag uuidTag = skullOwner.get("Id");
|
||||||
String uuidToString = "";
|
String uuidToString = "";
|
||||||
JsonNode node;
|
JsonNode node;
|
||||||
GameProfile gameProfile = new GameProfile(UUID.randomUUID(), "");
|
|
||||||
boolean retrieveUuidFromInternet = !(uuidTag instanceof IntArrayTag); // also covers null check
|
boolean retrieveUuidFromInternet = !(uuidTag instanceof IntArrayTag); // also covers null check
|
||||||
|
|
||||||
if (!retrieveUuidFromInternet) {
|
if (!retrieveUuidFromInternet) {
|
||||||
@ -577,15 +574,12 @@ public class SkinProvider {
|
|||||||
|
|
||||||
// Get textures from UUID
|
// Get textures from UUID
|
||||||
node = WebUtils.getJson("https://sessionserver.mojang.com/session/minecraft/profile/" + uuidToString);
|
node = WebUtils.getJson("https://sessionserver.mojang.com/session/minecraft/profile/" + uuidToString);
|
||||||
List<GameProfile.Property> profileProperties = new ArrayList<>();
|
|
||||||
JsonNode properties = node.get("properties");
|
JsonNode properties = node.get("properties");
|
||||||
if (properties == null) {
|
if (properties == null) {
|
||||||
GeyserImpl.getInstance().getLogger().debug("No properties found in Mojang response for " + uuidToString);
|
GeyserImpl.getInstance().getLogger().debug("No properties found in Mojang response for " + uuidToString);
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
profileProperties.add(new GameProfile.Property("textures", node.get("properties").get(0).get("value").asText()));
|
return node.get("properties").get(0).get("value").asText();
|
||||||
gameProfile.setProperties(profileProperties);
|
|
||||||
return gameProfile;
|
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
if (GeyserImpl.getInstance().getConfig().isDebugMode()) {
|
if (GeyserImpl.getInstance().getConfig().isDebugMode()) {
|
||||||
e.printStackTrace();
|
e.printStackTrace();
|
||||||
|
@ -50,7 +50,7 @@ public class SkullSkinManager extends SkinManager {
|
|||||||
|
|
||||||
public static void requestAndHandleSkin(PlayerEntity entity, GeyserSession session,
|
public static void requestAndHandleSkin(PlayerEntity entity, GeyserSession session,
|
||||||
Consumer<SkinProvider.Skin> skinConsumer) {
|
Consumer<SkinProvider.Skin> skinConsumer) {
|
||||||
GameProfileData data = GameProfileData.from(entity.getProfile());
|
GameProfileData data = GameProfileData.from(entity);
|
||||||
|
|
||||||
SkinProvider.requestSkin(entity.getUuid(), data.skinUrl(), true)
|
SkinProvider.requestSkin(entity.getUuid(), data.skinUrl(), true)
|
||||||
.whenCompleteAsync((skin, throwable) -> {
|
.whenCompleteAsync((skin, throwable) -> {
|
||||||
|
@ -41,13 +41,13 @@ import com.nukkitx.protocol.bedrock.data.inventory.stackrequestactions.StackRequ
|
|||||||
import com.nukkitx.protocol.bedrock.packet.ItemStackResponsePacket;
|
import com.nukkitx.protocol.bedrock.packet.ItemStackResponsePacket;
|
||||||
import it.unimi.dsi.fastutil.objects.Object2IntMap;
|
import it.unimi.dsi.fastutil.objects.Object2IntMap;
|
||||||
import it.unimi.dsi.fastutil.objects.Object2IntOpenHashMap;
|
import it.unimi.dsi.fastutil.objects.Object2IntOpenHashMap;
|
||||||
|
import org.geysermc.geyser.inventory.BedrockContainerSlot;
|
||||||
import org.geysermc.geyser.inventory.GeyserItemStack;
|
import org.geysermc.geyser.inventory.GeyserItemStack;
|
||||||
import org.geysermc.geyser.inventory.Inventory;
|
import org.geysermc.geyser.inventory.Inventory;
|
||||||
import org.geysermc.geyser.session.GeyserSession;
|
|
||||||
import org.geysermc.geyser.inventory.BedrockContainerSlot;
|
|
||||||
import org.geysermc.geyser.inventory.SlotType;
|
import org.geysermc.geyser.inventory.SlotType;
|
||||||
import org.geysermc.geyser.inventory.updater.UIInventoryUpdater;
|
import org.geysermc.geyser.inventory.updater.UIInventoryUpdater;
|
||||||
import org.geysermc.geyser.translator.inventory.item.BannerTranslator;
|
import org.geysermc.geyser.session.GeyserSession;
|
||||||
|
import org.geysermc.geyser.translator.inventory.item.nbt.BannerTranslator;
|
||||||
|
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
@ -35,28 +35,18 @@ import org.geysermc.geyser.registry.Registries;
|
|||||||
import org.geysermc.geyser.registry.type.ItemMapping;
|
import org.geysermc.geyser.registry.type.ItemMapping;
|
||||||
import org.geysermc.geyser.registry.type.ItemMappings;
|
import org.geysermc.geyser.registry.type.ItemMappings;
|
||||||
|
|
||||||
|
import java.util.Arrays;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
@ItemRemapper
|
@ItemRemapper
|
||||||
public class CompassTranslator extends ItemTranslator {
|
public class CompassTranslator extends ItemTranslator {
|
||||||
|
|
||||||
private final List<ItemMapping> appliedItems;
|
|
||||||
|
|
||||||
public CompassTranslator() {
|
|
||||||
appliedItems = Registries.ITEMS.forVersion(GameProtocol.DEFAULT_BEDROCK_CODEC.getProtocolVersion())
|
|
||||||
.getItems()
|
|
||||||
.values()
|
|
||||||
.stream()
|
|
||||||
.filter(entry -> entry.getJavaIdentifier().endsWith("compass"))
|
|
||||||
.collect(Collectors.toList());
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected ItemData.Builder translateToBedrock(ItemStack itemStack, ItemMapping mapping, ItemMappings mappings) {
|
protected ItemData.Builder translateToBedrock(ItemStack itemStack, ItemMapping mapping, ItemMappings mappings) {
|
||||||
if (isLodestoneCompass(itemStack.getNbt())) {
|
if (isLodestoneCompass(itemStack.getNbt())) {
|
||||||
// NBT will be translated in nbt/LodestoneCompassTranslator if applicable
|
// NBT will be translated in nbt/LodestoneCompassTranslator if applicable
|
||||||
return super.translateToBedrock(itemStack, mappings.getStoredItems().lodestoneCompass(), mappings);
|
return super.translateToBedrock(itemStack, mappings.getLodestoneCompass(), mappings);
|
||||||
}
|
}
|
||||||
return super.translateToBedrock(itemStack, mapping, mappings);
|
return super.translateToBedrock(itemStack, mapping, mappings);
|
||||||
}
|
}
|
||||||
@ -64,7 +54,7 @@ public class CompassTranslator extends ItemTranslator {
|
|||||||
@Override
|
@Override
|
||||||
protected ItemMapping getItemMapping(int javaId, CompoundTag nbt, ItemMappings mappings) {
|
protected ItemMapping getItemMapping(int javaId, CompoundTag nbt, ItemMappings mappings) {
|
||||||
if (isLodestoneCompass(nbt)) {
|
if (isLodestoneCompass(nbt)) {
|
||||||
return mappings.getStoredItems().lodestoneCompass();
|
return mappings.getLodestoneCompass();
|
||||||
}
|
}
|
||||||
return super.getItemMapping(javaId, nbt, mappings);
|
return super.getItemMapping(javaId, nbt, mappings);
|
||||||
}
|
}
|
||||||
@ -89,6 +79,9 @@ public class CompassTranslator extends ItemTranslator {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public List<ItemMapping> getAppliedItems() {
|
public List<ItemMapping> getAppliedItems() {
|
||||||
return appliedItems;
|
return Arrays.stream(Registries.ITEMS.forVersion(GameProtocol.DEFAULT_BEDROCK_CODEC.getProtocolVersion())
|
||||||
|
.getItems())
|
||||||
|
.filter(entry -> entry.getJavaIdentifier().endsWith("compass"))
|
||||||
|
.collect(Collectors.toList());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,68 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2019-2022 GeyserMC. http://geysermc.org
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
* of this software and associated documentation files (the "Software"), to deal
|
||||||
|
* in the Software without restriction, including without limitation the rights
|
||||||
|
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
* copies of the Software, and to permit persons to whom the Software is
|
||||||
|
* furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in
|
||||||
|
* all copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
|
* THE SOFTWARE.
|
||||||
|
*
|
||||||
|
* @author GeyserMC
|
||||||
|
* @link https://github.com/GeyserMC/Geyser
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.geysermc.geyser.translator.inventory.item;
|
||||||
|
|
||||||
|
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.Tag;
|
||||||
|
import com.nukkitx.protocol.bedrock.data.inventory.ItemData;
|
||||||
|
import org.geysermc.geyser.network.GameProtocol;
|
||||||
|
import org.geysermc.geyser.registry.Registries;
|
||||||
|
import org.geysermc.geyser.registry.type.ItemMapping;
|
||||||
|
import org.geysermc.geyser.registry.type.ItemMappings;
|
||||||
|
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
@ItemRemapper
|
||||||
|
public class FilledMapTranslator extends ItemTranslator {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected ItemData.Builder translateToBedrock(ItemStack itemStack, ItemMapping mapping, ItemMappings mappings) {
|
||||||
|
ItemData.Builder builder = super.translateToBedrock(itemStack, mapping, mappings);
|
||||||
|
CompoundTag nbt = itemStack.getNbt();
|
||||||
|
if (nbt != null && nbt.get("display") instanceof CompoundTag display) {
|
||||||
|
// Note: damage 5 treasure map, 6 ???
|
||||||
|
Tag mapColor = display.get("MapColor");
|
||||||
|
if (mapColor != null && mapColor.getValue() instanceof Number color) {
|
||||||
|
// Java Edition allows any color; Bedrock only allows some. So let's take what colors we can get
|
||||||
|
switch (color.intValue()) {
|
||||||
|
case 3830373 -> builder.damage(3); // Ocean Monument
|
||||||
|
case 5393476 -> builder.damage(4); // Woodland explorer
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return builder;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<ItemMapping> getAppliedItems() {
|
||||||
|
return Collections.singletonList(
|
||||||
|
Registries.ITEMS.forVersion(GameProtocol.DEFAULT_BEDROCK_CODEC.getProtocolVersion())
|
||||||
|
.getMapping("minecraft:filled_map")
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
@ -47,6 +47,7 @@ import org.geysermc.geyser.translator.text.MessageTranslator;
|
|||||||
import org.geysermc.geyser.util.FileUtils;
|
import org.geysermc.geyser.util.FileUtils;
|
||||||
|
|
||||||
import javax.annotation.Nonnull;
|
import javax.annotation.Nonnull;
|
||||||
|
import java.lang.reflect.InvocationTargetException;
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
@ -71,11 +72,11 @@ public abstract class ItemTranslator {
|
|||||||
|
|
||||||
try {
|
try {
|
||||||
if (NbtItemStackTranslator.class.isAssignableFrom(clazz)) {
|
if (NbtItemStackTranslator.class.isAssignableFrom(clazz)) {
|
||||||
NbtItemStackTranslator nbtItemTranslator = (NbtItemStackTranslator) clazz.newInstance();
|
NbtItemStackTranslator nbtItemTranslator = (NbtItemStackTranslator) clazz.getDeclaredConstructor().newInstance();
|
||||||
loadedNbtItemTranslators.put(nbtItemTranslator, priority);
|
loadedNbtItemTranslators.put(nbtItemTranslator, priority);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
ItemTranslator itemStackTranslator = (ItemTranslator) clazz.newInstance();
|
ItemTranslator itemStackTranslator = (ItemTranslator) clazz.getDeclaredConstructor().newInstance();
|
||||||
List<ItemMapping> appliedItems = itemStackTranslator.getAppliedItems();
|
List<ItemMapping> appliedItems = itemStackTranslator.getAppliedItems();
|
||||||
for (ItemMapping item : appliedItems) {
|
for (ItemMapping item : appliedItems) {
|
||||||
ItemTranslator registered = ITEM_STACK_TRANSLATORS.get(item.getJavaId());
|
ItemTranslator registered = ITEM_STACK_TRANSLATORS.get(item.getJavaId());
|
||||||
@ -87,7 +88,7 @@ public abstract class ItemTranslator {
|
|||||||
}
|
}
|
||||||
ITEM_STACK_TRANSLATORS.put(item.getJavaId(), itemStackTranslator);
|
ITEM_STACK_TRANSLATORS.put(item.getJavaId(), itemStackTranslator);
|
||||||
}
|
}
|
||||||
} catch (InstantiationException | IllegalAccessException e) {
|
} catch (InstantiationException | InvocationTargetException | IllegalAccessException | NoSuchMethodException e) {
|
||||||
GeyserImpl.getInstance().getLogger().error("Could not instantiate annotated item translator " + clazz.getCanonicalName());
|
GeyserImpl.getInstance().getLogger().error("Could not instantiate annotated item translator " + clazz.getCanonicalName());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -302,13 +303,16 @@ public abstract class ItemTranslator {
|
|||||||
return new ItemStack(mapping.getJavaId(), itemData.getCount(), this.translateToJavaNBT("", itemData.getTag()));
|
return new ItemStack(mapping.getJavaId(), itemData.getCount(), this.translateToJavaNBT("", itemData.getTag()));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Used for initialization only and only called once.
|
||||||
|
*/
|
||||||
public abstract List<ItemMapping> getAppliedItems();
|
public abstract List<ItemMapping> getAppliedItems();
|
||||||
|
|
||||||
protected ItemMapping getItemMapping(int javaId, CompoundTag nbt, ItemMappings mappings) {
|
protected ItemMapping getItemMapping(int javaId, CompoundTag nbt, ItemMappings mappings) {
|
||||||
return mappings.getMapping(javaId);
|
return mappings.getMapping(javaId);
|
||||||
}
|
}
|
||||||
|
|
||||||
public NbtMap translateNbtToBedrock(CompoundTag tag) {
|
protected NbtMap translateNbtToBedrock(CompoundTag tag) {
|
||||||
NbtMapBuilder builder = NbtMap.builder();
|
NbtMapBuilder builder = NbtMap.builder();
|
||||||
if (tag.getValue() != null && !tag.getValue().isEmpty()) {
|
if (tag.getValue() != null && !tag.getValue().isEmpty()) {
|
||||||
for (String str : tag.getValue().keySet()) {
|
for (String str : tag.getValue().keySet()) {
|
||||||
@ -387,7 +391,7 @@ public abstract class ItemTranslator {
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
public CompoundTag translateToJavaNBT(String name, NbtMap tag) {
|
private CompoundTag translateToJavaNBT(String name, NbtMap tag) {
|
||||||
CompoundTag javaTag = new CompoundTag(name);
|
CompoundTag javaTag = new CompoundTag(name);
|
||||||
Map<String, Tag> javaValue = javaTag.getValue();
|
Map<String, Tag> javaValue = javaTag.getValue();
|
||||||
if (tag != null && !tag.isEmpty()) {
|
if (tag != null && !tag.isEmpty()) {
|
||||||
|
@ -29,12 +29,12 @@ import com.github.steveice10.opennbt.tag.builtin.CompoundTag;
|
|||||||
import org.geysermc.geyser.session.GeyserSession;
|
import org.geysermc.geyser.session.GeyserSession;
|
||||||
import org.geysermc.geyser.registry.type.ItemMapping;
|
import org.geysermc.geyser.registry.type.ItemMapping;
|
||||||
|
|
||||||
public class NbtItemStackTranslator {
|
public abstract class NbtItemStackTranslator {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Translate the item NBT to Bedrock
|
* Translate the item NBT to Bedrock
|
||||||
* @param session the client's current session
|
* @param session the client's current session
|
||||||
* @param itemTag the item's CompoundTag
|
* @param itemTag the item's CompoundTag (cloned from Geyser's cached copy)
|
||||||
* @param mapping Geyser's item mapping
|
* @param mapping Geyser's item mapping
|
||||||
*/
|
*/
|
||||||
public void translateToBedrock(GeyserSession session, CompoundTag itemTag, ItemMapping mapping) {
|
public void translateToBedrock(GeyserSession session, CompoundTag itemTag, ItemMapping mapping) {
|
||||||
|
@ -36,23 +36,13 @@ import org.geysermc.geyser.registry.Registries;
|
|||||||
import org.geysermc.geyser.registry.type.ItemMapping;
|
import org.geysermc.geyser.registry.type.ItemMapping;
|
||||||
import org.geysermc.geyser.registry.type.ItemMappings;
|
import org.geysermc.geyser.registry.type.ItemMappings;
|
||||||
|
|
||||||
|
import java.util.Arrays;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
@ItemRemapper
|
@ItemRemapper
|
||||||
public class PotionTranslator extends ItemTranslator {
|
public class PotionTranslator extends ItemTranslator {
|
||||||
|
|
||||||
private final List<ItemMapping> appliedItems;
|
|
||||||
|
|
||||||
public PotionTranslator() {
|
|
||||||
appliedItems = Registries.ITEMS.forVersion(GameProtocol.DEFAULT_BEDROCK_CODEC.getProtocolVersion())
|
|
||||||
.getItems()
|
|
||||||
.values()
|
|
||||||
.stream()
|
|
||||||
.filter(entry -> entry.getJavaIdentifier().endsWith("potion"))
|
|
||||||
.collect(Collectors.toList());
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected ItemData.Builder translateToBedrock(ItemStack itemStack, ItemMapping mapping, ItemMappings mappings) {
|
protected ItemData.Builder translateToBedrock(ItemStack itemStack, ItemMapping mapping, ItemMappings mappings) {
|
||||||
if (itemStack.getNbt() == null) return super.translateToBedrock(itemStack, mapping, mappings);
|
if (itemStack.getNbt() == null) return super.translateToBedrock(itemStack, mapping, mappings);
|
||||||
@ -84,6 +74,9 @@ public class PotionTranslator extends ItemTranslator {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public List<ItemMapping> getAppliedItems() {
|
public List<ItemMapping> getAppliedItems() {
|
||||||
return appliedItems;
|
return Arrays.stream(Registries.ITEMS.forVersion(GameProtocol.DEFAULT_BEDROCK_CODEC.getProtocolVersion())
|
||||||
|
.getItems())
|
||||||
|
.filter(entry -> entry.getJavaIdentifier().endsWith("potion"))
|
||||||
|
.collect(Collectors.toList());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -36,28 +36,16 @@ import org.geysermc.geyser.registry.Registries;
|
|||||||
import org.geysermc.geyser.registry.type.ItemMapping;
|
import org.geysermc.geyser.registry.type.ItemMapping;
|
||||||
import org.geysermc.geyser.registry.type.ItemMappings;
|
import org.geysermc.geyser.registry.type.ItemMappings;
|
||||||
|
|
||||||
|
import java.util.Arrays;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
@ItemRemapper
|
@ItemRemapper
|
||||||
public class TippedArrowTranslator extends ItemTranslator {
|
public class TippedArrowTranslator extends ItemTranslator {
|
||||||
|
|
||||||
private final List<ItemMapping> appliedItems;
|
|
||||||
|
|
||||||
private static final int TIPPED_ARROW_JAVA_ID = Registries.ITEMS.forVersion(GameProtocol.DEFAULT_BEDROCK_CODEC.getProtocolVersion())
|
private static final int TIPPED_ARROW_JAVA_ID = Registries.ITEMS.forVersion(GameProtocol.DEFAULT_BEDROCK_CODEC.getProtocolVersion())
|
||||||
.getMapping("minecraft:tipped_arrow")
|
.getMapping("minecraft:tipped_arrow")
|
||||||
.getJavaId();
|
.getJavaId();
|
||||||
|
|
||||||
public TippedArrowTranslator() {
|
|
||||||
appliedItems = Registries.ITEMS.forVersion(GameProtocol.DEFAULT_BEDROCK_CODEC.getProtocolVersion())
|
|
||||||
.getItems()
|
|
||||||
.values()
|
|
||||||
.stream()
|
|
||||||
.filter(entry -> entry.getJavaIdentifier().contains("arrow")
|
|
||||||
&& !entry.getJavaIdentifier().contains("spectral"))
|
|
||||||
.collect(Collectors.toList());
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected ItemData.Builder translateToBedrock(ItemStack itemStack, ItemMapping mapping, ItemMappings mappings) {
|
protected ItemData.Builder translateToBedrock(ItemStack itemStack, ItemMapping mapping, ItemMappings mappings) {
|
||||||
if (!mapping.getJavaIdentifier().equals("minecraft:tipped_arrow") || itemStack.getNbt() == null) {
|
if (!mapping.getJavaIdentifier().equals("minecraft:tipped_arrow") || itemStack.getNbt() == null) {
|
||||||
@ -93,6 +81,10 @@ public class TippedArrowTranslator extends ItemTranslator {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public List<ItemMapping> getAppliedItems() {
|
public List<ItemMapping> getAppliedItems() {
|
||||||
return appliedItems;
|
return Arrays.stream(Registries.ITEMS.forVersion(GameProtocol.DEFAULT_BEDROCK_CODEC.getProtocolVersion())
|
||||||
|
.getItems())
|
||||||
|
.filter(entry -> entry.getJavaIdentifier().contains("arrow")
|
||||||
|
&& !entry.getJavaIdentifier().contains("spectral"))
|
||||||
|
.collect(Collectors.toList());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -23,29 +23,25 @@
|
|||||||
* @link https://github.com/GeyserMC/Geyser
|
* @link https://github.com/GeyserMC/Geyser
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package org.geysermc.geyser.translator.inventory.item;
|
package org.geysermc.geyser.translator.inventory.item.nbt;
|
||||||
|
|
||||||
import com.github.steveice10.mc.protocol.data.game.entity.metadata.ItemStack;
|
|
||||||
import com.github.steveice10.opennbt.tag.builtin.*;
|
import com.github.steveice10.opennbt.tag.builtin.*;
|
||||||
import com.nukkitx.nbt.NbtList;
|
import com.nukkitx.nbt.NbtList;
|
||||||
import com.nukkitx.nbt.NbtMap;
|
import com.nukkitx.nbt.NbtMap;
|
||||||
import com.nukkitx.nbt.NbtMapBuilder;
|
|
||||||
import com.nukkitx.nbt.NbtType;
|
import com.nukkitx.nbt.NbtType;
|
||||||
import com.nukkitx.protocol.bedrock.data.inventory.ItemData;
|
|
||||||
import org.geysermc.geyser.network.GameProtocol;
|
import org.geysermc.geyser.network.GameProtocol;
|
||||||
import org.geysermc.geyser.registry.Registries;
|
import org.geysermc.geyser.registry.Registries;
|
||||||
import org.geysermc.geyser.registry.type.ItemMapping;
|
import org.geysermc.geyser.registry.type.ItemMapping;
|
||||||
import org.geysermc.geyser.registry.type.ItemMappings;
|
import org.geysermc.geyser.session.GeyserSession;
|
||||||
|
import org.geysermc.geyser.translator.inventory.item.ItemRemapper;
|
||||||
|
import org.geysermc.geyser.translator.inventory.item.NbtItemStackTranslator;
|
||||||
|
|
||||||
import javax.annotation.Nonnull;
|
import javax.annotation.Nonnull;
|
||||||
import java.util.ArrayList;
|
import java.util.*;
|
||||||
import java.util.HashMap;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.Map;
|
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
@ItemRemapper
|
@ItemRemapper
|
||||||
public class BannerTranslator extends ItemTranslator {
|
public class BannerTranslator extends NbtItemStackTranslator {
|
||||||
/**
|
/**
|
||||||
* Holds what a Java ominous banner pattern looks like.
|
* Holds what a Java ominous banner pattern looks like.
|
||||||
*
|
*
|
||||||
@ -80,10 +76,8 @@ public class BannerTranslator extends ItemTranslator {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public BannerTranslator() {
|
public BannerTranslator() {
|
||||||
appliedItems = Registries.ITEMS.forVersion(GameProtocol.DEFAULT_BEDROCK_CODEC.getProtocolVersion())
|
appliedItems = Arrays.stream(Registries.ITEMS.forVersion(GameProtocol.DEFAULT_BEDROCK_CODEC.getProtocolVersion())
|
||||||
.getItems()
|
.getItems())
|
||||||
.values()
|
|
||||||
.stream()
|
|
||||||
.filter(entry -> entry.getJavaIdentifier().endsWith("banner"))
|
.filter(entry -> entry.getJavaIdentifier().endsWith("banner"))
|
||||||
.collect(Collectors.toList());
|
.collect(Collectors.toList());
|
||||||
}
|
}
|
||||||
@ -117,21 +111,6 @@ public class BannerTranslator extends ItemTranslator {
|
|||||||
.build();
|
.build();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* 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(List<NbtMap> patterns) {
|
|
||||||
List<Tag> tagsList = new ArrayList<>();
|
|
||||||
for (NbtMap patternTag : patterns) {
|
|
||||||
tagsList.add(getJavaBannerPattern(patternTag));
|
|
||||||
}
|
|
||||||
|
|
||||||
return new ListTag("Patterns", tagsList);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Convert the Bedrock edition banner pattern nbt to Java edition
|
* Convert the Bedrock edition banner pattern nbt to Java edition
|
||||||
*
|
*
|
||||||
@ -146,62 +125,54 @@ public class BannerTranslator extends ItemTranslator {
|
|||||||
return new CompoundTag("", tags);
|
return new CompoundTag("", tags);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
/**
|
||||||
protected ItemData.Builder translateToBedrock(ItemStack itemStack, ItemMapping mapping, ItemMappings mappings) {
|
* Convert a list of patterns from Java nbt to Bedrock nbt, or vice versa (we just need to invert the color)
|
||||||
if (itemStack.getNbt() == null) {
|
*
|
||||||
return super.translateToBedrock(itemStack, mapping, mappings);
|
* @param patterns The patterns to convert
|
||||||
|
*/
|
||||||
|
private void invertBannerColors(ListTag patterns) {
|
||||||
|
for (Tag patternTag : patterns.getValue()) {
|
||||||
|
IntTag color = ((CompoundTag) patternTag).get("Color");
|
||||||
|
color.setValue(15 - color.getValue());
|
||||||
}
|
}
|
||||||
|
|
||||||
ItemData.Builder builder = super.translateToBedrock(itemStack, mapping, mappings);
|
|
||||||
|
|
||||||
CompoundTag blockEntityTag = itemStack.getNbt().get("BlockEntityTag");
|
|
||||||
if (blockEntityTag != null && blockEntityTag.get("Patterns") instanceof ListTag patterns) {
|
|
||||||
NbtMapBuilder nbtBuilder = builder.build().getTag().toBuilder(); //TODO fix ugly hack
|
|
||||||
if (patterns.equals(OMINOUS_BANNER_PATTERN)) {
|
|
||||||
// Remove the current patterns and set the ominous banner type
|
|
||||||
nbtBuilder.remove("Patterns");
|
|
||||||
nbtBuilder.putInt("Type", 1);
|
|
||||||
} else {
|
|
||||||
nbtBuilder.put("Patterns", convertBannerPattern(patterns));
|
|
||||||
}
|
|
||||||
|
|
||||||
builder.tag(nbtBuilder.build());
|
|
||||||
}
|
|
||||||
|
|
||||||
return builder;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public ItemStack translateToJava(ItemData itemData, ItemMapping mapping, ItemMappings mappings) {
|
public void translateToBedrock(GeyserSession session, CompoundTag itemTag, ItemMapping mapping) {
|
||||||
if (itemData.getTag() == null) {
|
CompoundTag blockEntityTag = itemTag.get("BlockEntityTag");
|
||||||
return super.translateToJava(itemData, mapping, mappings);
|
if (blockEntityTag != null && blockEntityTag.get("Patterns") instanceof ListTag patterns) {
|
||||||
|
if (patterns.equals(OMINOUS_BANNER_PATTERN)) {
|
||||||
|
// Remove the current patterns and set the ominous banner type
|
||||||
|
itemTag.put(new IntTag("Type", 1));
|
||||||
|
} else {
|
||||||
|
invertBannerColors(patterns);
|
||||||
|
itemTag.put(patterns);
|
||||||
|
}
|
||||||
|
itemTag.remove("BlockEntityTag");
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
ItemStack itemStack = super.translateToJava(itemData, mapping, mappings);
|
@Override
|
||||||
|
public void translateToJava(CompoundTag itemTag, ItemMapping mapping) {
|
||||||
NbtMap nbtTag = itemData.getTag();
|
if (itemTag.get("Type") instanceof IntTag type && type.getValue() == 1) {
|
||||||
if (nbtTag.containsKey("Type", NbtType.INT) && nbtTag.getInt("Type") == 1) {
|
|
||||||
// Ominous banner pattern
|
// Ominous banner pattern
|
||||||
itemStack.getNbt().remove("Type");
|
itemTag.remove("Type");
|
||||||
CompoundTag blockEntityTag = new CompoundTag("BlockEntityTag");
|
CompoundTag blockEntityTag = new CompoundTag("BlockEntityTag");
|
||||||
blockEntityTag.put(OMINOUS_BANNER_PATTERN);
|
blockEntityTag.put(OMINOUS_BANNER_PATTERN);
|
||||||
|
|
||||||
itemStack.getNbt().put(blockEntityTag);
|
itemTag.put(blockEntityTag);
|
||||||
} else if (nbtTag.containsKey("Patterns", NbtType.LIST)) {
|
} else if (itemTag.get("Patterns") instanceof ListTag patterns) {
|
||||||
List<NbtMap> patterns = nbtTag.getList("Patterns", NbtType.COMPOUND);
|
|
||||||
|
|
||||||
CompoundTag blockEntityTag = new CompoundTag("BlockEntityTag");
|
CompoundTag blockEntityTag = new CompoundTag("BlockEntityTag");
|
||||||
blockEntityTag.put(convertBannerPattern(patterns));
|
invertBannerColors(patterns);
|
||||||
|
blockEntityTag.put(patterns);
|
||||||
|
|
||||||
itemStack.getNbt().put(blockEntityTag);
|
itemTag.put(blockEntityTag);
|
||||||
itemStack.getNbt().remove("Patterns"); // Remove the old Bedrock patterns list
|
itemTag.remove("Patterns"); // Remove the old Bedrock patterns list
|
||||||
}
|
}
|
||||||
|
|
||||||
return itemStack;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public List<ItemMapping> getAppliedItems() {
|
public boolean acceptItem(ItemMapping mapping) {
|
||||||
return appliedItems;
|
return appliedItems.contains(mapping);
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -121,10 +121,6 @@ public class EnchantmentTranslator extends NbtItemStackTranslator {
|
|||||||
|
|
||||||
|
|
||||||
private CompoundTag remapEnchantment(CompoundTag tag) {
|
private CompoundTag remapEnchantment(CompoundTag tag) {
|
||||||
Tag javaEnchLvl = tag.get("lvl");
|
|
||||||
if (!(javaEnchLvl instanceof ShortTag || javaEnchLvl instanceof IntTag))
|
|
||||||
return null;
|
|
||||||
|
|
||||||
Tag javaEnchId = tag.get("id");
|
Tag javaEnchId = tag.get("id");
|
||||||
if (!(javaEnchId instanceof StringTag))
|
if (!(javaEnchId instanceof StringTag))
|
||||||
return null;
|
return null;
|
||||||
@ -135,9 +131,12 @@ public class EnchantmentTranslator extends NbtItemStackTranslator {
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Tag javaEnchLvl = tag.get("lvl");
|
||||||
|
|
||||||
CompoundTag bedrockTag = new CompoundTag("");
|
CompoundTag bedrockTag = new CompoundTag("");
|
||||||
bedrockTag.put(new ShortTag("id", (short) enchantment.ordinal()));
|
bedrockTag.put(new ShortTag("id", (short) enchantment.ordinal()));
|
||||||
bedrockTag.put(new ShortTag("lvl", ((Number) javaEnchLvl.getValue()).shortValue()));
|
// If the tag cannot parse, Java Edition 1.18.2 sets to 0
|
||||||
|
bedrockTag.put(new ShortTag("lvl", javaEnchLvl != null && javaEnchLvl.getValue() instanceof Number lvl ? lvl.shortValue() : (short) 0));
|
||||||
return bedrockTag;
|
return bedrockTag;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -28,9 +28,10 @@ package org.geysermc.geyser.translator.level.block.entity;
|
|||||||
import com.github.steveice10.mc.protocol.data.game.level.block.BlockEntityType;
|
import com.github.steveice10.mc.protocol.data.game.level.block.BlockEntityType;
|
||||||
import com.github.steveice10.opennbt.tag.builtin.CompoundTag;
|
import com.github.steveice10.opennbt.tag.builtin.CompoundTag;
|
||||||
import com.github.steveice10.opennbt.tag.builtin.ListTag;
|
import com.github.steveice10.opennbt.tag.builtin.ListTag;
|
||||||
|
import com.github.steveice10.opennbt.tag.builtin.Tag;
|
||||||
import com.nukkitx.nbt.NbtMapBuilder;
|
import com.nukkitx.nbt.NbtMapBuilder;
|
||||||
import org.geysermc.geyser.translator.inventory.item.BannerTranslator;
|
|
||||||
import org.geysermc.geyser.level.block.BlockStateValues;
|
import org.geysermc.geyser.level.block.BlockStateValues;
|
||||||
|
import org.geysermc.geyser.translator.inventory.item.nbt.BannerTranslator;
|
||||||
|
|
||||||
@BlockEntity(type = BlockEntityType.BANNER)
|
@BlockEntity(type = BlockEntityType.BANNER)
|
||||||
public class BannerBlockEntityTranslator extends BlockEntityTranslator implements RequiresBlockState {
|
public class BannerBlockEntityTranslator extends BlockEntityTranslator implements RequiresBlockState {
|
||||||
@ -45,8 +46,7 @@ public class BannerBlockEntityTranslator extends BlockEntityTranslator implement
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (tag.contains("Patterns")) {
|
if (tag.get("Patterns") instanceof ListTag patterns) {
|
||||||
ListTag patterns = tag.get("Patterns");
|
|
||||||
if (patterns.equals(BannerTranslator.OMINOUS_BANNER_PATTERN)) {
|
if (patterns.equals(BannerTranslator.OMINOUS_BANNER_PATTERN)) {
|
||||||
// This is an ominous banner; don't try to translate the raw patterns (it doesn't translate correctly)
|
// This is an ominous banner; don't try to translate the raw patterns (it doesn't translate correctly)
|
||||||
// and tell the Bedrock client that this is an ominous banner
|
// and tell the Bedrock client that this is an ominous banner
|
||||||
@ -56,8 +56,9 @@ public class BannerBlockEntityTranslator extends BlockEntityTranslator implement
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (tag.contains("CustomName")) {
|
Tag customName = tag.get("CustomName");
|
||||||
builder.put("CustomName", tag.get("CustomName").getValue());
|
if (customName != null) {
|
||||||
|
builder.put("CustomName", customName.getValue());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,48 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (c) 2019-2022 GeyserMC. http://geysermc.org
|
|
||||||
*
|
|
||||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
||||||
* of this software and associated documentation files (the "Software"), to deal
|
|
||||||
* in the Software without restriction, including without limitation the rights
|
|
||||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
||||||
* copies of the Software, and to permit persons to whom the Software is
|
|
||||||
* furnished to do so, subject to the following conditions:
|
|
||||||
*
|
|
||||||
* The above copyright notice and this permission notice shall be included in
|
|
||||||
* all copies or substantial portions of the Software.
|
|
||||||
*
|
|
||||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
||||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
||||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
||||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
||||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
||||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
|
||||||
* THE SOFTWARE.
|
|
||||||
*
|
|
||||||
* @author GeyserMC
|
|
||||||
* @link https://github.com/GeyserMC/Geyser
|
|
||||||
*/
|
|
||||||
|
|
||||||
package org.geysermc.geyser.translator.level.block.entity;
|
|
||||||
|
|
||||||
import com.github.steveice10.mc.protocol.data.game.entity.metadata.Position;
|
|
||||||
import com.nukkitx.math.vector.Vector3i;
|
|
||||||
import com.nukkitx.protocol.bedrock.packet.BlockEventPacket;
|
|
||||||
import org.geysermc.geyser.session.GeyserSession;
|
|
||||||
import org.geysermc.geyser.level.block.BlockStateValues;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Does not implement BlockEntityTranslator because it's only a block entity in Bedrock
|
|
||||||
*/
|
|
||||||
public class NoteblockBlockEntityTranslator {
|
|
||||||
|
|
||||||
public static void translate(GeyserSession session, Position position) {
|
|
||||||
int blockState = session.getGeyser().getWorldManager().getBlockAt(session, position);
|
|
||||||
BlockEventPacket blockEventPacket = new BlockEventPacket();
|
|
||||||
blockEventPacket.setBlockPosition(Vector3i.from(position.getX(), position.getY(), position.getZ()));
|
|
||||||
blockEventPacket.setEventType(0);
|
|
||||||
blockEventPacket.setEventData(BlockStateValues.getNoteblockPitch(blockState));
|
|
||||||
session.sendUpstreamPacket(blockEventPacket);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
@ -25,7 +25,6 @@
|
|||||||
|
|
||||||
package org.geysermc.geyser.translator.level.block.entity;
|
package org.geysermc.geyser.translator.level.block.entity;
|
||||||
|
|
||||||
import com.github.steveice10.mc.auth.data.GameProfile;
|
|
||||||
import com.github.steveice10.mc.protocol.data.game.level.block.BlockEntityType;
|
import com.github.steveice10.mc.protocol.data.game.level.block.BlockEntityType;
|
||||||
import com.github.steveice10.opennbt.tag.builtin.CompoundTag;
|
import com.github.steveice10.opennbt.tag.builtin.CompoundTag;
|
||||||
import com.github.steveice10.opennbt.tag.builtin.ListTag;
|
import com.github.steveice10.opennbt.tag.builtin.ListTag;
|
||||||
@ -35,15 +34,12 @@ import com.nukkitx.math.vector.Vector3i;
|
|||||||
import com.nukkitx.nbt.NbtMapBuilder;
|
import com.nukkitx.nbt.NbtMapBuilder;
|
||||||
import com.nukkitx.protocol.bedrock.data.entity.EntityFlag;
|
import com.nukkitx.protocol.bedrock.data.entity.EntityFlag;
|
||||||
import org.geysermc.geyser.entity.type.player.SkullPlayerEntity;
|
import org.geysermc.geyser.entity.type.player.SkullPlayerEntity;
|
||||||
import org.geysermc.geyser.session.GeyserSession;
|
|
||||||
import org.geysermc.geyser.level.block.BlockStateValues;
|
import org.geysermc.geyser.level.block.BlockStateValues;
|
||||||
|
import org.geysermc.geyser.session.GeyserSession;
|
||||||
import org.geysermc.geyser.skin.SkinProvider;
|
import org.geysermc.geyser.skin.SkinProvider;
|
||||||
import org.geysermc.geyser.skin.SkullSkinManager;
|
import org.geysermc.geyser.skin.SkullSkinManager;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.LinkedHashMap;
|
import java.util.LinkedHashMap;
|
||||||
import java.util.List;
|
|
||||||
import java.util.UUID;
|
|
||||||
import java.util.concurrent.CompletableFuture;
|
import java.util.concurrent.CompletableFuture;
|
||||||
import java.util.concurrent.TimeUnit;
|
import java.util.concurrent.TimeUnit;
|
||||||
|
|
||||||
@ -62,7 +58,7 @@ public class SkullBlockEntityTranslator extends BlockEntityTranslator implements
|
|||||||
builder.put("SkullType", skullVariant);
|
builder.put("SkullType", skullVariant);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static CompletableFuture<GameProfile> getProfile(CompoundTag tag) {
|
private static CompletableFuture<String> getTextures(CompoundTag tag) {
|
||||||
CompoundTag owner = tag.get("SkullOwner");
|
CompoundTag owner = tag.get("SkullOwner");
|
||||||
if (owner != null) {
|
if (owner != null) {
|
||||||
CompoundTag properties = owner.get("Properties");
|
CompoundTag properties = owner.get("Properties");
|
||||||
@ -73,13 +69,7 @@ public class SkullBlockEntityTranslator extends BlockEntityTranslator implements
|
|||||||
ListTag textures = properties.get("textures");
|
ListTag textures = properties.get("textures");
|
||||||
LinkedHashMap<?,?> tag1 = (LinkedHashMap<?,?>) textures.get(0).getValue();
|
LinkedHashMap<?,?> tag1 = (LinkedHashMap<?,?>) textures.get(0).getValue();
|
||||||
StringTag texture = (StringTag) tag1.get("Value");
|
StringTag texture = (StringTag) tag1.get("Value");
|
||||||
|
return CompletableFuture.completedFuture(texture.getValue());
|
||||||
List<GameProfile.Property> profileProperties = new ArrayList<>();
|
|
||||||
|
|
||||||
GameProfile gameProfile = new GameProfile(UUID.randomUUID(), "");
|
|
||||||
profileProperties.add(new GameProfile.Property("textures", texture.getValue()));
|
|
||||||
gameProfile.setProperties(profileProperties);
|
|
||||||
return CompletableFuture.completedFuture(gameProfile);
|
|
||||||
}
|
}
|
||||||
return CompletableFuture.completedFuture(null);
|
return CompletableFuture.completedFuture(null);
|
||||||
}
|
}
|
||||||
@ -108,21 +98,21 @@ public class SkullBlockEntityTranslator extends BlockEntityTranslator implements
|
|||||||
Vector3i blockPosition = Vector3i.from(posX, posY, posZ);
|
Vector3i blockPosition = Vector3i.from(posX, posY, posZ);
|
||||||
Vector3f entityPosition = Vector3f.from(x, y, z);
|
Vector3f entityPosition = Vector3f.from(x, y, z);
|
||||||
|
|
||||||
getProfile(tag).whenComplete((gameProfile, throwable) -> {
|
getTextures(tag).whenComplete((texturesProperty, throwable) -> {
|
||||||
if (gameProfile == null) {
|
if (texturesProperty == null) {
|
||||||
session.getGeyser().getLogger().debug("Custom skull with invalid SkullOwner tag: " + blockPosition + " " + tag);
|
session.getGeyser().getLogger().debug("Custom skull with invalid SkullOwner tag: " + blockPosition + " " + tag);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (session.getEventLoop().inEventLoop()) {
|
if (session.getEventLoop().inEventLoop()) {
|
||||||
spawnPlayer(session, gameProfile, blockPosition, entityPosition, rotation, blockState);
|
spawnPlayer(session, texturesProperty, blockPosition, entityPosition, rotation, blockState);
|
||||||
} else {
|
} else {
|
||||||
session.executeInEventLoop(() -> spawnPlayer(session, gameProfile, blockPosition, entityPosition, rotation, blockState));
|
session.executeInEventLoop(() -> spawnPlayer(session, texturesProperty, blockPosition, entityPosition, rotation, blockState));
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void spawnPlayer(GeyserSession session, GameProfile profile, Vector3i blockPosition,
|
private static void spawnPlayer(GeyserSession session, String texturesProperty, Vector3i blockPosition,
|
||||||
Vector3f entityPosition, float rotation, int blockState) {
|
Vector3f entityPosition, float rotation, int blockState) {
|
||||||
long geyserId = session.getEntityCache().getNextEntityId().incrementAndGet();
|
long geyserId = session.getEntityCache().getNextEntityId().incrementAndGet();
|
||||||
|
|
||||||
@ -132,7 +122,7 @@ public class SkullBlockEntityTranslator extends BlockEntityTranslator implements
|
|||||||
existingSkull.despawnEntity(blockPosition);
|
existingSkull.despawnEntity(blockPosition);
|
||||||
}
|
}
|
||||||
|
|
||||||
SkullPlayerEntity player = new SkullPlayerEntity(session, geyserId, profile, entityPosition, rotation, blockState);
|
SkullPlayerEntity player = new SkullPlayerEntity(session, geyserId, entityPosition, rotation, blockState, texturesProperty);
|
||||||
|
|
||||||
// Cache entity
|
// Cache entity
|
||||||
session.getSkullCache().put(blockPosition, player);
|
session.getSkullCache().put(blockPosition, player);
|
||||||
|
@ -139,7 +139,8 @@ public class BedrockInventoryTransactionTranslator extends PacketTranslator<Inve
|
|||||||
case ITEM_USE:
|
case ITEM_USE:
|
||||||
switch (packet.getActionType()) {
|
switch (packet.getActionType()) {
|
||||||
case 0 -> {
|
case 0 -> {
|
||||||
Vector3i blockPos = BlockUtils.getBlockPosition(packet.getBlockPosition(), packet.getBlockFace());
|
final Vector3i packetBlockPosition = packet.getBlockPosition();
|
||||||
|
Vector3i blockPos = BlockUtils.getBlockPosition(packetBlockPosition, packet.getBlockFace());
|
||||||
|
|
||||||
if (session.getGeyser().getConfig().isDisableBedrockScaffolding()) {
|
if (session.getGeyser().getConfig().isDisableBedrockScaffolding()) {
|
||||||
float yaw = session.getPlayerEntity().getYaw();
|
float yaw = session.getPlayerEntity().getYaw();
|
||||||
@ -159,8 +160,8 @@ public class BedrockInventoryTransactionTranslator extends PacketTranslator<Inve
|
|||||||
// Check to make sure the client isn't spamming interaction
|
// Check to make sure the client isn't spamming interaction
|
||||||
// Based on Nukkit 1.0, with changes to ensure holding down still works
|
// Based on Nukkit 1.0, with changes to ensure holding down still works
|
||||||
boolean hasAlreadyClicked = System.currentTimeMillis() - session.getLastInteractionTime() < 110.0 &&
|
boolean hasAlreadyClicked = System.currentTimeMillis() - session.getLastInteractionTime() < 110.0 &&
|
||||||
packet.getBlockPosition().distanceSquared(session.getLastInteractionBlockPosition()) < 0.00001;
|
packetBlockPosition.distanceSquared(session.getLastInteractionBlockPosition()) < 0.00001;
|
||||||
session.setLastInteractionBlockPosition(packet.getBlockPosition());
|
session.setLastInteractionBlockPosition(packetBlockPosition);
|
||||||
session.setLastInteractionPlayerPosition(session.getPlayerEntity().getPosition());
|
session.setLastInteractionPlayerPosition(session.getPlayerEntity().getPosition());
|
||||||
if (hasAlreadyClicked) {
|
if (hasAlreadyClicked) {
|
||||||
break;
|
break;
|
||||||
@ -204,22 +205,48 @@ public class BedrockInventoryTransactionTranslator extends PacketTranslator<Inve
|
|||||||
playerPosition = playerPosition.sub(0, (EntityDefinitions.PLAYER.offset() - 0.2f), 0);
|
playerPosition = playerPosition.sub(0, (EntityDefinitions.PLAYER.offset() - 0.2f), 0);
|
||||||
} // else, we don't have to modify the position
|
} // else, we don't have to modify the position
|
||||||
|
|
||||||
float diffX = playerPosition.getX() - packet.getBlockPosition().getX();
|
boolean creative = session.getGameMode() == GameMode.CREATIVE;
|
||||||
float diffY = playerPosition.getY() - packet.getBlockPosition().getY();
|
|
||||||
float diffZ = playerPosition.getZ() - packet.getBlockPosition().getZ();
|
float diffX = playerPosition.getX() - packetBlockPosition.getX();
|
||||||
|
float diffY = playerPosition.getY() - packetBlockPosition.getY();
|
||||||
|
float diffZ = playerPosition.getZ() - packetBlockPosition.getZ();
|
||||||
if (((diffX * diffX) + (diffY * diffY) + (diffZ * diffZ)) >
|
if (((diffX * diffX) + (diffY * diffY) + (diffZ * diffZ)) >
|
||||||
(session.getGameMode().equals(GameMode.CREATIVE) ? CREATIVE_EYE_HEIGHT_PLACE_DISTANCE : SURVIVAL_EYE_HEIGHT_PLACE_DISTANCE)) {
|
(creative ? CREATIVE_EYE_HEIGHT_PLACE_DISTANCE : SURVIVAL_EYE_HEIGHT_PLACE_DISTANCE)) {
|
||||||
restoreCorrectBlock(session, blockPos, packet);
|
restoreCorrectBlock(session, blockPos, packet);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
double clickPositionFullX = (double) packetBlockPosition.getX() + (double) packet.getClickPosition().getX();
|
||||||
|
double clickPositionFullY = (double) packetBlockPosition.getY() + (double) packet.getClickPosition().getY();
|
||||||
|
double clickPositionFullZ = (double) packetBlockPosition.getZ() + (double) packet.getClickPosition().getZ();
|
||||||
|
|
||||||
|
// More recent Paper check - https://github.com/PaperMC/Paper/blob/87e11bf7fdf48ecdf3e1cae383c368b9b61d7df9/patches/server/0470-Move-range-check-for-block-placing-up.patch
|
||||||
|
double clickDiffX = playerPosition.getX() - clickPositionFullX;
|
||||||
|
double clickDiffY = playerPosition.getY() - clickPositionFullY;
|
||||||
|
double clickDiffZ = playerPosition.getZ() - clickPositionFullZ;
|
||||||
|
if (((clickDiffX * clickDiffX) + (clickDiffY * clickDiffY) + (clickDiffZ * clickDiffZ)) >
|
||||||
|
(creative ? CREATIVE_EYE_HEIGHT_PLACE_DISTANCE : SURVIVAL_EYE_HEIGHT_PLACE_DISTANCE)) {
|
||||||
|
restoreCorrectBlock(session, blockPos, packet);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
Vector3f blockCenter = Vector3f.from(packetBlockPosition.getX() + 0.5f, packetBlockPosition.getY() + 0.5f, packetBlockPosition.getZ() + 0.5f);
|
||||||
// Vanilla check
|
// Vanilla check
|
||||||
if (!(session.getPlayerEntity().getPosition().sub(0, EntityDefinitions.PLAYER.offset(), 0)
|
if (!(session.getPlayerEntity().getPosition().sub(0, EntityDefinitions.PLAYER.offset(), 0)
|
||||||
.distanceSquared(packet.getBlockPosition().toFloat().add(0.5f, 0.5f, 0.5f)) < MAXIMUM_BLOCK_PLACING_DISTANCE)) {
|
.distanceSquared(blockCenter) < MAXIMUM_BLOCK_PLACING_DISTANCE)) {
|
||||||
// The client thinks that its blocks have been successfully placed. Restore the server's blocks instead.
|
// The client thinks that its blocks have been successfully placed. Restore the server's blocks instead.
|
||||||
restoreCorrectBlock(session, blockPos, packet);
|
restoreCorrectBlock(session, blockPos, packet);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// More recent vanilla check (as of 1.18.2)
|
||||||
|
double clickDistanceX = clickPositionFullX - blockCenter.getX();
|
||||||
|
double clickDistanceY = clickPositionFullY - blockCenter.getY();
|
||||||
|
double clickDistanceZ = clickPositionFullZ - blockCenter.getZ();
|
||||||
|
if (!(Math.abs(clickDistanceX) < 1.0000001D && Math.abs(clickDistanceY) < 1.0000001D && Math.abs(clickDistanceZ) < 1.0000001D)) {
|
||||||
|
restoreCorrectBlock(session, blockPos, packet);
|
||||||
|
return;
|
||||||
|
}
|
||||||
/*
|
/*
|
||||||
Block place checks end - client is good to go
|
Block place checks end - client is good to go
|
||||||
*/
|
*/
|
||||||
@ -284,7 +311,7 @@ public class BedrockInventoryTransactionTranslator extends PacketTranslator<Inve
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ItemMapping handItem = mappings.getMapping(packet.getItemInHand());
|
ItemMapping handItem = session.getPlayerInventory().getItemInHand().getMapping(session);
|
||||||
if (handItem.isBlock()) {
|
if (handItem.isBlock()) {
|
||||||
session.setLastBlockPlacePosition(blockPos);
|
session.setLastBlockPlacePosition(blockPos);
|
||||||
session.setLastBlockPlacedId(handItem.getJavaIdentifier());
|
session.setLastBlockPlacedId(handItem.getJavaIdentifier());
|
||||||
|
@ -30,6 +30,7 @@ import com.github.steveice10.mc.protocol.packet.ingame.serverbound.player.Server
|
|||||||
import com.github.steveice10.mc.protocol.packet.ingame.serverbound.player.ServerboundUseItemPacket;
|
import com.github.steveice10.mc.protocol.packet.ingame.serverbound.player.ServerboundUseItemPacket;
|
||||||
import com.nukkitx.protocol.bedrock.data.inventory.ContainerId;
|
import com.nukkitx.protocol.bedrock.data.inventory.ContainerId;
|
||||||
import com.nukkitx.protocol.bedrock.packet.MobEquipmentPacket;
|
import com.nukkitx.protocol.bedrock.packet.MobEquipmentPacket;
|
||||||
|
import org.geysermc.geyser.inventory.GeyserItemStack;
|
||||||
import org.geysermc.geyser.session.GeyserSession;
|
import org.geysermc.geyser.session.GeyserSession;
|
||||||
import org.geysermc.geyser.translator.protocol.PacketTranslator;
|
import org.geysermc.geyser.translator.protocol.PacketTranslator;
|
||||||
import org.geysermc.geyser.translator.protocol.Translator;
|
import org.geysermc.geyser.translator.protocol.Translator;
|
||||||
@ -42,8 +43,9 @@ public class BedrockMobEquipmentTranslator extends PacketTranslator<MobEquipment
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void translate(GeyserSession session, MobEquipmentPacket packet) {
|
public void translate(GeyserSession session, MobEquipmentPacket packet) {
|
||||||
if (!session.isSpawned() || packet.getHotbarSlot() > 8 ||
|
int newSlot = packet.getHotbarSlot();
|
||||||
packet.getContainerId() != ContainerId.INVENTORY || session.getPlayerInventory().getHeldItemSlot() == packet.getHotbarSlot()) {
|
if (!session.isSpawned() || newSlot > 8 || packet.getContainerId() != ContainerId.INVENTORY
|
||||||
|
|| session.getPlayerInventory().getHeldItemSlot() == newSlot) {
|
||||||
// For the last condition - Don't update the slot if the slot is the same - not Java Edition behavior and messes with plugins such as Grief Prevention
|
// For the last condition - Don't update the slot if the slot is the same - not Java Edition behavior and messes with plugins such as Grief Prevention
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -51,12 +53,15 @@ public class BedrockMobEquipmentTranslator extends PacketTranslator<MobEquipment
|
|||||||
// Send book update before switching hotbar slot
|
// Send book update before switching hotbar slot
|
||||||
session.getBookEditCache().checkForSend();
|
session.getBookEditCache().checkForSend();
|
||||||
|
|
||||||
session.getPlayerInventory().setHeldItemSlot(packet.getHotbarSlot());
|
GeyserItemStack oldItem = session.getPlayerInventory().getItemInHand();
|
||||||
|
session.getPlayerInventory().setHeldItemSlot(newSlot);
|
||||||
|
|
||||||
ServerboundSetCarriedItemPacket setCarriedItemPacket = new ServerboundSetCarriedItemPacket(packet.getHotbarSlot());
|
ServerboundSetCarriedItemPacket setCarriedItemPacket = new ServerboundSetCarriedItemPacket(newSlot);
|
||||||
session.sendDownstreamPacket(setCarriedItemPacket);
|
session.sendDownstreamPacket(setCarriedItemPacket);
|
||||||
|
|
||||||
if (session.isSneaking() && session.getPlayerInventory().getItemInHand().getJavaId() == session.getItemMappings().getStoredItems().shield().getJavaId()) {
|
GeyserItemStack newItem = session.getPlayerInventory().getItemInHand();
|
||||||
|
|
||||||
|
if (session.isSneaking() && newItem.getJavaId() == session.getItemMappings().getStoredItems().shield().getJavaId()) {
|
||||||
// Activate shield since we are already sneaking
|
// Activate shield since we are already sneaking
|
||||||
// (No need to send a release item packet - Java doesn't do this when swapping items)
|
// (No need to send a release item packet - Java doesn't do this when swapping items)
|
||||||
// Required to do it a tick later or else it doesn't register
|
// Required to do it a tick later or else it doesn't register
|
||||||
@ -64,8 +69,10 @@ public class BedrockMobEquipmentTranslator extends PacketTranslator<MobEquipment
|
|||||||
50, TimeUnit.MILLISECONDS);
|
50, TimeUnit.MILLISECONDS);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Java sends a cooldown indicator whenever you switch an item
|
if (oldItem.getJavaId() != newItem.getJavaId()) {
|
||||||
CooldownUtils.sendCooldown(session);
|
// Java sends a cooldown indicator whenever you switch to a new item type
|
||||||
|
CooldownUtils.sendCooldown(session);
|
||||||
|
}
|
||||||
|
|
||||||
// Update the interactive tag, if an entity is present
|
// Update the interactive tag, if an entity is present
|
||||||
if (session.getMouseoverEntity() != null) {
|
if (session.getMouseoverEntity() != null) {
|
||||||
|
@ -172,8 +172,7 @@ public class JavaUpdateRecipesTranslator extends PacketTranslator<ClientboundUpd
|
|||||||
// Sort the list by each output item's Java identifier - this is how it's sorted on Java, and therefore
|
// Sort the list by each output item's Java identifier - this is how it's sorted on Java, and therefore
|
||||||
// We can get the correct order for button pressing
|
// We can get the correct order for button pressing
|
||||||
data.getValue().sort(Comparator.comparing((stoneCuttingRecipeData ->
|
data.getValue().sort(Comparator.comparing((stoneCuttingRecipeData ->
|
||||||
session.getItemMappings().getItems()
|
session.getItemMappings().getMapping(stoneCuttingRecipeData.getResult())
|
||||||
.getOrDefault(stoneCuttingRecipeData.getResult().getId(), ItemMapping.AIR)
|
|
||||||
.getJavaIdentifier())));
|
.getJavaIdentifier())));
|
||||||
|
|
||||||
// Now that it's sorted, let's translate these recipes
|
// Now that it's sorted, let's translate these recipes
|
||||||
@ -229,7 +228,7 @@ public class JavaUpdateRecipesTranslator extends PacketTranslator<ClientboundUpd
|
|||||||
GroupedItem groupedItem = entry.getKey();
|
GroupedItem groupedItem = entry.getKey();
|
||||||
int idCount = 0;
|
int idCount = 0;
|
||||||
//not optimal
|
//not optimal
|
||||||
for (ItemMapping mapping : session.getItemMappings().getItems().values()) {
|
for (ItemMapping mapping : session.getItemMappings().getItems()) {
|
||||||
if (mapping.getBedrockId() == groupedItem.id) {
|
if (mapping.getBedrockId() == groupedItem.id) {
|
||||||
idCount++;
|
idCount++;
|
||||||
}
|
}
|
||||||
|
@ -25,6 +25,7 @@
|
|||||||
|
|
||||||
package org.geysermc.geyser.translator.protocol.java.entity.player;
|
package org.geysermc.geyser.translator.protocol.java.entity.player;
|
||||||
|
|
||||||
|
import com.github.steveice10.mc.auth.data.GameProfile;
|
||||||
import com.github.steveice10.mc.protocol.data.game.PlayerListEntry;
|
import com.github.steveice10.mc.protocol.data.game.PlayerListEntry;
|
||||||
import com.github.steveice10.mc.protocol.data.game.PlayerListEntryAction;
|
import com.github.steveice10.mc.protocol.data.game.PlayerListEntryAction;
|
||||||
import com.github.steveice10.mc.protocol.packet.ingame.clientbound.ClientboundPlayerInfoPacket;
|
import com.github.steveice10.mc.protocol.packet.ingame.clientbound.ClientboundPlayerInfoPacket;
|
||||||
@ -50,31 +51,38 @@ public class JavaPlayerInfoTranslator extends PacketTranslator<ClientboundPlayer
|
|||||||
for (PlayerListEntry entry : packet.getEntries()) {
|
for (PlayerListEntry entry : packet.getEntries()) {
|
||||||
switch (packet.getAction()) {
|
switch (packet.getAction()) {
|
||||||
case ADD_PLAYER -> {
|
case ADD_PLAYER -> {
|
||||||
|
GameProfile profile = entry.getProfile();
|
||||||
PlayerEntity playerEntity;
|
PlayerEntity playerEntity;
|
||||||
boolean self = entry.getProfile().getId().equals(session.getPlayerEntity().getUuid());
|
boolean self = profile.getId().equals(session.getPlayerEntity().getUuid());
|
||||||
|
|
||||||
if (self) {
|
if (self) {
|
||||||
// Entity is ourself
|
// Entity is ourself
|
||||||
playerEntity = session.getPlayerEntity();
|
playerEntity = session.getPlayerEntity();
|
||||||
} else {
|
} else {
|
||||||
playerEntity = session.getEntityCache().getPlayerEntity(entry.getProfile().getId());
|
playerEntity = session.getEntityCache().getPlayerEntity(profile.getId());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
GameProfile.Property textures = profile.getProperty("textures");
|
||||||
|
String texturesProperty = textures == null ? null : textures.getValue();
|
||||||
|
|
||||||
if (playerEntity == null) {
|
if (playerEntity == null) {
|
||||||
// It's a new player
|
// It's a new player
|
||||||
playerEntity = new PlayerEntity(
|
playerEntity = new PlayerEntity(
|
||||||
session,
|
session,
|
||||||
-1,
|
-1,
|
||||||
session.getEntityCache().getNextEntityId().incrementAndGet(),
|
session.getEntityCache().getNextEntityId().incrementAndGet(),
|
||||||
entry.getProfile(),
|
profile.getId(),
|
||||||
Vector3f.ZERO,
|
Vector3f.ZERO,
|
||||||
Vector3f.ZERO,
|
Vector3f.ZERO,
|
||||||
0, 0, 0
|
0, 0, 0,
|
||||||
|
profile.getName(),
|
||||||
|
texturesProperty
|
||||||
);
|
);
|
||||||
|
|
||||||
session.getEntityCache().addPlayerEntity(playerEntity);
|
session.getEntityCache().addPlayerEntity(playerEntity);
|
||||||
} else {
|
} else {
|
||||||
playerEntity.setProfile(entry.getProfile());
|
playerEntity.setUsername(profile.getName());
|
||||||
|
playerEntity.setTexturesProperty(texturesProperty);
|
||||||
}
|
}
|
||||||
|
|
||||||
playerEntity.setPlayerList(true);
|
playerEntity.setPlayerList(true);
|
||||||
|
@ -48,7 +48,9 @@ public class JavaAddPlayerTranslator extends PacketTranslator<ClientboundAddPlay
|
|||||||
PlayerEntity entity;
|
PlayerEntity entity;
|
||||||
if (packet.getUuid().equals(session.getPlayerEntity().getUuid())) {
|
if (packet.getUuid().equals(session.getPlayerEntity().getUuid())) {
|
||||||
// Server is sending a fake version of the current player
|
// Server is sending a fake version of the current player
|
||||||
entity = new PlayerEntity(session, packet.getEntityId(), session.getEntityCache().getNextEntityId().incrementAndGet(), session.getPlayerEntity().getProfile(), position, Vector3f.ZERO, yaw, pitch, headYaw);
|
entity = new PlayerEntity(session, packet.getEntityId(), session.getEntityCache().getNextEntityId().incrementAndGet(),
|
||||||
|
session.getPlayerEntity().getUuid(), position, Vector3f.ZERO, yaw, pitch, headYaw, session.getPlayerEntity().getUsername(),
|
||||||
|
session.getPlayerEntity().getTexturesProperty());
|
||||||
} else {
|
} else {
|
||||||
entity = session.getEntityCache().getPlayerEntity(packet.getUuid());
|
entity = session.getEntityCache().getPlayerEntity(packet.getUuid());
|
||||||
if (entity == null) {
|
if (entity == null) {
|
||||||
|
@ -35,14 +35,13 @@ import com.nukkitx.protocol.bedrock.packet.BlockEntityDataPacket;
|
|||||||
import com.nukkitx.protocol.bedrock.packet.BlockEventPacket;
|
import com.nukkitx.protocol.bedrock.packet.BlockEventPacket;
|
||||||
import it.unimi.dsi.fastutil.objects.Object2IntMaps;
|
import it.unimi.dsi.fastutil.objects.Object2IntMaps;
|
||||||
import org.geysermc.common.PlatformType;
|
import org.geysermc.common.PlatformType;
|
||||||
|
import org.geysermc.geyser.level.block.BlockStateValues;
|
||||||
|
import org.geysermc.geyser.level.physics.Direction;
|
||||||
import org.geysermc.geyser.session.GeyserSession;
|
import org.geysermc.geyser.session.GeyserSession;
|
||||||
import org.geysermc.geyser.session.cache.PistonCache;
|
import org.geysermc.geyser.session.cache.PistonCache;
|
||||||
|
import org.geysermc.geyser.translator.level.block.entity.PistonBlockEntity;
|
||||||
import org.geysermc.geyser.translator.protocol.PacketTranslator;
|
import org.geysermc.geyser.translator.protocol.PacketTranslator;
|
||||||
import org.geysermc.geyser.translator.protocol.Translator;
|
import org.geysermc.geyser.translator.protocol.Translator;
|
||||||
import org.geysermc.geyser.level.block.BlockStateValues;
|
|
||||||
import org.geysermc.geyser.translator.level.block.entity.NoteblockBlockEntityTranslator;
|
|
||||||
import org.geysermc.geyser.translator.level.block.entity.PistonBlockEntity;
|
|
||||||
import org.geysermc.geyser.level.physics.Direction;
|
|
||||||
|
|
||||||
@Translator(packet = ClientboundBlockEventPacket.class)
|
@Translator(packet = ClientboundBlockEventPacket.class)
|
||||||
public class JavaBlockEventTranslator extends PacketTranslator<ClientboundBlockEventPacket> {
|
public class JavaBlockEventTranslator extends PacketTranslator<ClientboundBlockEventPacket> {
|
||||||
@ -50,8 +49,9 @@ public class JavaBlockEventTranslator extends PacketTranslator<ClientboundBlockE
|
|||||||
@Override
|
@Override
|
||||||
public void translate(GeyserSession session, ClientboundBlockEventPacket packet) {
|
public void translate(GeyserSession session, ClientboundBlockEventPacket packet) {
|
||||||
BlockEventPacket blockEventPacket = new BlockEventPacket();
|
BlockEventPacket blockEventPacket = new BlockEventPacket();
|
||||||
blockEventPacket.setBlockPosition(Vector3i.from(packet.getPosition().getX(),
|
Position position = packet.getPosition();
|
||||||
packet.getPosition().getY(), packet.getPosition().getZ()));
|
Vector3i vector = Vector3i.from(position.getX(), position.getY(), position.getZ());
|
||||||
|
blockEventPacket.setBlockPosition(vector);
|
||||||
if (packet.getValue() instanceof ChestValue value) {
|
if (packet.getValue() instanceof ChestValue value) {
|
||||||
blockEventPacket.setEventType(1);
|
blockEventPacket.setEventType(1);
|
||||||
blockEventPacket.setEventData(value.getViewers() > 0 ? 1 : 0);
|
blockEventPacket.setEventData(value.getViewers() > 0 ? 1 : 0);
|
||||||
@ -60,11 +60,12 @@ public class JavaBlockEventTranslator extends PacketTranslator<ClientboundBlockE
|
|||||||
blockEventPacket.setEventType(1);
|
blockEventPacket.setEventType(1);
|
||||||
session.sendUpstreamPacket(blockEventPacket);
|
session.sendUpstreamPacket(blockEventPacket);
|
||||||
} else if (packet.getValue() instanceof NoteBlockValue) {
|
} else if (packet.getValue() instanceof NoteBlockValue) {
|
||||||
NoteblockBlockEntityTranslator.translate(session, packet.getPosition());
|
int blockState = session.getGeyser().getWorldManager().getBlockAt(session, position);
|
||||||
|
blockEventPacket.setEventData(BlockStateValues.getNoteblockPitch(blockState));
|
||||||
|
session.sendUpstreamPacket(blockEventPacket);
|
||||||
} else if (packet.getValue() instanceof PistonValue pistonValue) {
|
} else if (packet.getValue() instanceof PistonValue pistonValue) {
|
||||||
PistonValueType action = (PistonValueType) packet.getType();
|
PistonValueType action = (PistonValueType) packet.getType();
|
||||||
Direction direction = Direction.fromPistonValue(pistonValue);
|
Direction direction = Direction.fromPistonValue(pistonValue);
|
||||||
Vector3i position = Vector3i.from(packet.getPosition().getX(), packet.getPosition().getY(), packet.getPosition().getZ());
|
|
||||||
PistonCache pistonCache = session.getPistonCache();
|
PistonCache pistonCache = session.getPistonCache();
|
||||||
|
|
||||||
if (session.getGeyser().getPlatformType() == PlatformType.SPIGOT) {
|
if (session.getGeyser().getPlatformType() == PlatformType.SPIGOT) {
|
||||||
@ -77,20 +78,20 @@ public class JavaBlockEventTranslator extends PacketTranslator<ClientboundBlockE
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (action != PistonValueType.CANCELLED_MID_PUSH) {
|
if (action != PistonValueType.CANCELLED_MID_PUSH) {
|
||||||
Vector3i blockInFrontPos = position.add(direction.getUnitVector());
|
Vector3i blockInFrontPos = vector.add(direction.getUnitVector());
|
||||||
int blockInFront = session.getGeyser().getWorldManager().getBlockAt(session, blockInFrontPos);
|
int blockInFront = session.getGeyser().getWorldManager().getBlockAt(session, blockInFrontPos);
|
||||||
if (blockInFront != BlockStateValues.JAVA_AIR_ID) {
|
if (blockInFront != BlockStateValues.JAVA_AIR_ID) {
|
||||||
// Piston pulled something
|
// Piston pulled something
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
PistonBlockEntity blockEntity = pistonCache.getPistons().computeIfAbsent(position, pos -> new PistonBlockEntity(session, pos, direction, true, true));
|
PistonBlockEntity blockEntity = pistonCache.getPistons().computeIfAbsent(vector, pos -> new PistonBlockEntity(session, pos, direction, true, true));
|
||||||
if (blockEntity.getAction() != action) {
|
if (blockEntity.getAction() != action) {
|
||||||
blockEntity.setAction(action, Object2IntMaps.emptyMap());
|
blockEntity.setAction(action, Object2IntMaps.emptyMap());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
PistonBlockEntity blockEntity = pistonCache.getPistons().computeIfAbsent(position, pos -> {
|
PistonBlockEntity blockEntity = pistonCache.getPistons().computeIfAbsent(vector, pos -> {
|
||||||
int blockId = session.getGeyser().getWorldManager().getBlockAt(session, position);
|
int blockId = session.getGeyser().getWorldManager().getBlockAt(session, position);
|
||||||
boolean sticky = BlockStateValues.isStickyPiston(blockId);
|
boolean sticky = BlockStateValues.isStickyPiston(blockId);
|
||||||
boolean extended = action != PistonValueType.PUSHING;
|
boolean extended = action != PistonValueType.PUSHING;
|
||||||
@ -106,10 +107,8 @@ public class JavaBlockEventTranslator extends PacketTranslator<ClientboundBlockE
|
|||||||
session.sendUpstreamPacket(blockEventPacket);
|
session.sendUpstreamPacket(blockEventPacket);
|
||||||
} else if (packet.getValue() instanceof GenericBlockValue bellValue && packet.getBlockId() == BlockStateValues.JAVA_BELL_ID) {
|
} else if (packet.getValue() instanceof GenericBlockValue bellValue && packet.getBlockId() == BlockStateValues.JAVA_BELL_ID) {
|
||||||
// Bells - needed to show ring from other players
|
// Bells - needed to show ring from other players
|
||||||
Position position = packet.getPosition();
|
|
||||||
|
|
||||||
BlockEntityDataPacket blockEntityPacket = new BlockEntityDataPacket();
|
BlockEntityDataPacket blockEntityPacket = new BlockEntityDataPacket();
|
||||||
blockEntityPacket.setBlockPosition(Vector3i.from(position.getX(), position.getY(), position.getZ()));
|
blockEntityPacket.setBlockPosition(vector);
|
||||||
|
|
||||||
NbtMapBuilder builder = NbtMap.builder();
|
NbtMapBuilder builder = NbtMap.builder();
|
||||||
builder.putInt("x", position.getX());
|
builder.putInt("x", position.getX());
|
||||||
|
@ -37,11 +37,14 @@ public class JavaClearTitlesTranslator extends PacketTranslator<ClientboundClear
|
|||||||
@Override
|
@Override
|
||||||
public void translate(GeyserSession session, ClientboundClearTitlesPacket packet) {
|
public void translate(GeyserSession session, ClientboundClearTitlesPacket packet) {
|
||||||
SetTitlePacket titlePacket = new SetTitlePacket();
|
SetTitlePacket titlePacket = new SetTitlePacket();
|
||||||
// TODO handle packet.isResetTimes()
|
|
||||||
titlePacket.setType(SetTitlePacket.Type.CLEAR);
|
titlePacket.setType(SetTitlePacket.Type.CLEAR);
|
||||||
titlePacket.setText("");
|
titlePacket.setText("");
|
||||||
titlePacket.setXuid("");
|
titlePacket.setXuid("");
|
||||||
titlePacket.setPlatformOnlineId("");
|
titlePacket.setPlatformOnlineId("");
|
||||||
session.sendUpstreamPacket(titlePacket);
|
session.sendUpstreamPacket(titlePacket);
|
||||||
|
|
||||||
|
if (packet.isResetTimes()) {
|
||||||
|
session.getWorldCache().resetTitleTimes(true);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -38,6 +38,8 @@ public class JavaSetTitleTextTranslator extends PacketTranslator<ClientboundSetT
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void translate(GeyserSession session, ClientboundSetTitleTextPacket packet) {
|
public void translate(GeyserSession session, ClientboundSetTitleTextPacket packet) {
|
||||||
|
session.getWorldCache().synchronizeCorrectTitleTimes();
|
||||||
|
|
||||||
String text;
|
String text;
|
||||||
if (packet.getText() == null || Component.empty().equals(packet.getText())) { // This can happen, see https://github.com/KyoriPowered/adventure/issues/447
|
if (packet.getText() == null || Component.empty().equals(packet.getText())) { // This can happen, see https://github.com/KyoriPowered/adventure/issues/447
|
||||||
text = " ";
|
text = " ";
|
||||||
|
@ -36,12 +36,17 @@ public class JavaSetTitlesAnimationTranslator extends PacketTranslator<Clientbou
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void translate(GeyserSession session, ClientboundSetTitlesAnimationPacket packet) {
|
public void translate(GeyserSession session, ClientboundSetTitlesAnimationPacket packet) {
|
||||||
|
int fadeInTime = packet.getFadeIn();
|
||||||
|
int stayTime = packet.getStay();
|
||||||
|
int fadeOutTime = packet.getFadeOut();
|
||||||
|
session.getWorldCache().setTitleTimes(fadeInTime, stayTime, fadeOutTime);
|
||||||
|
|
||||||
SetTitlePacket titlePacket = new SetTitlePacket();
|
SetTitlePacket titlePacket = new SetTitlePacket();
|
||||||
titlePacket.setType(SetTitlePacket.Type.TIMES);
|
titlePacket.setType(SetTitlePacket.Type.TIMES);
|
||||||
titlePacket.setText("");
|
titlePacket.setText("");
|
||||||
titlePacket.setFadeInTime(packet.getFadeIn());
|
titlePacket.setFadeInTime(fadeInTime);
|
||||||
titlePacket.setFadeOutTime(packet.getFadeOut());
|
titlePacket.setFadeOutTime(fadeOutTime);
|
||||||
titlePacket.setStayTime(packet.getStay());
|
titlePacket.setStayTime(stayTime);
|
||||||
titlePacket.setXuid("");
|
titlePacket.setXuid("");
|
||||||
titlePacket.setPlatformOnlineId("");
|
titlePacket.setPlatformOnlineId("");
|
||||||
session.sendUpstreamPacket(titlePacket);
|
session.sendUpstreamPacket(titlePacket);
|
||||||
|
@ -57,8 +57,19 @@ public class CooldownUtils {
|
|||||||
if (sessionPreference == CooldownType.DISABLED) return;
|
if (sessionPreference == CooldownType.DISABLED) return;
|
||||||
|
|
||||||
if (session.getAttackSpeed() == 0.0 || session.getAttackSpeed() > 20) return; // 0.0 usually happens on login and causes issues with visuals; anything above 20 means a plugin like OldCombatMechanics is being used
|
if (session.getAttackSpeed() == 0.0 || session.getAttackSpeed() > 20) return; // 0.0 usually happens on login and causes issues with visuals; anything above 20 means a plugin like OldCombatMechanics is being used
|
||||||
// Needs to be sent or no subtitle packet is recognized by the client
|
// Set the times to stay a bit with no fade in nor out
|
||||||
SetTitlePacket titlePacket = new SetTitlePacket();
|
SetTitlePacket titlePacket = new SetTitlePacket();
|
||||||
|
titlePacket.setType(SetTitlePacket.Type.TIMES);
|
||||||
|
titlePacket.setStayTime(1000);
|
||||||
|
titlePacket.setText("");
|
||||||
|
titlePacket.setXuid("");
|
||||||
|
titlePacket.setPlatformOnlineId("");
|
||||||
|
session.sendUpstreamPacket(titlePacket);
|
||||||
|
|
||||||
|
session.getWorldCache().markTitleTimesAsIncorrect();
|
||||||
|
|
||||||
|
// Needs to be sent or no subtitle packet is recognized by the client
|
||||||
|
titlePacket = new SetTitlePacket();
|
||||||
titlePacket.setType(SetTitlePacket.Type.TITLE);
|
titlePacket.setType(SetTitlePacket.Type.TITLE);
|
||||||
titlePacket.setText(" ");
|
titlePacket.setText(" ");
|
||||||
titlePacket.setXuid("");
|
titlePacket.setXuid("");
|
||||||
@ -85,9 +96,6 @@ public class CooldownUtils {
|
|||||||
titlePacket.setType(SetTitlePacket.Type.SUBTITLE);
|
titlePacket.setType(SetTitlePacket.Type.SUBTITLE);
|
||||||
}
|
}
|
||||||
titlePacket.setText(getTitle(session));
|
titlePacket.setText(getTitle(session));
|
||||||
titlePacket.setFadeInTime(0);
|
|
||||||
titlePacket.setFadeOutTime(5);
|
|
||||||
titlePacket.setStayTime(2);
|
|
||||||
titlePacket.setXuid("");
|
titlePacket.setXuid("");
|
||||||
titlePacket.setPlatformOnlineId("");
|
titlePacket.setPlatformOnlineId("");
|
||||||
session.sendUpstreamPacket(titlePacket);
|
session.sendUpstreamPacket(titlePacket);
|
||||||
@ -96,11 +104,7 @@ public class CooldownUtils {
|
|||||||
computeCooldown(session, sessionPreference, lastHitTime), 50, TimeUnit.MILLISECONDS); // Updated per tick. 1000 divided by 20 ticks equals 50
|
computeCooldown(session, sessionPreference, lastHitTime), 50, TimeUnit.MILLISECONDS); // Updated per tick. 1000 divided by 20 ticks equals 50
|
||||||
} else {
|
} else {
|
||||||
SetTitlePacket removeTitlePacket = new SetTitlePacket();
|
SetTitlePacket removeTitlePacket = new SetTitlePacket();
|
||||||
if (sessionPreference == CooldownType.ACTIONBAR) {
|
removeTitlePacket.setType(SetTitlePacket.Type.CLEAR);
|
||||||
removeTitlePacket.setType(SetTitlePacket.Type.ACTIONBAR);
|
|
||||||
} else {
|
|
||||||
removeTitlePacket.setType(SetTitlePacket.Type.SUBTITLE);
|
|
||||||
}
|
|
||||||
removeTitlePacket.setText(" ");
|
removeTitlePacket.setText(" ");
|
||||||
removeTitlePacket.setXuid("");
|
removeTitlePacket.setXuid("");
|
||||||
removeTitlePacket.setPlatformOnlineId("");
|
removeTitlePacket.setPlatformOnlineId("");
|
||||||
|
@ -29,21 +29,27 @@ import com.github.steveice10.opennbt.tag.builtin.*;
|
|||||||
import it.unimi.dsi.fastutil.ints.Int2IntMap;
|
import it.unimi.dsi.fastutil.ints.Int2IntMap;
|
||||||
import org.geysermc.geyser.session.GeyserSession;
|
import org.geysermc.geyser.session.GeyserSession;
|
||||||
|
|
||||||
|
import javax.annotation.Nullable;
|
||||||
|
|
||||||
public class ItemUtils {
|
public class ItemUtils {
|
||||||
private static Int2IntMap DYE_COLORS = null;
|
private static Int2IntMap DYE_COLORS = null;
|
||||||
|
|
||||||
public static int getEnchantmentLevel(CompoundTag itemNBTData, String enchantmentId) {
|
public static int getEnchantmentLevel(@Nullable CompoundTag itemNBTData, String enchantmentId) {
|
||||||
ListTag enchantments = (itemNBTData == null ? null : itemNBTData.get("Enchantments"));
|
if (itemNBTData == null) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
ListTag enchantments = itemNBTData.get("Enchantments");
|
||||||
if (enchantments != null) {
|
if (enchantments != null) {
|
||||||
int enchantmentLevel = 0;
|
|
||||||
for (Tag tag : enchantments) {
|
for (Tag tag : enchantments) {
|
||||||
CompoundTag enchantment = (CompoundTag) tag;
|
CompoundTag enchantment = (CompoundTag) tag;
|
||||||
StringTag enchantId = enchantment.get("id");
|
StringTag enchantId = enchantment.get("id");
|
||||||
if (enchantId.getValue().equals(enchantmentId)) {
|
if (enchantId.getValue().equals(enchantmentId)) {
|
||||||
enchantmentLevel = (int) ((ShortTag) enchantment.get("lvl")).getValue();
|
Tag lvl = enchantment.get("lvl");
|
||||||
|
if (lvl != null && lvl.getValue() instanceof Number number) {
|
||||||
|
return number.intValue();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return enchantmentLevel;
|
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -62,7 +62,7 @@ public class SettingsUtils {
|
|||||||
|
|
||||||
// Client can only see its coordinates if reducedDebugInfo is disabled and coordinates are enabled in geyser config.
|
// Client can only see its coordinates if reducedDebugInfo is disabled and coordinates are enabled in geyser config.
|
||||||
if (session.getPreferencesCache().isAllowShowCoordinates()) {
|
if (session.getPreferencesCache().isAllowShowCoordinates()) {
|
||||||
builder.toggle("geyser.settings.option.coordinates", session.getPreferencesCache().isPrefersShowCoordinates());
|
builder.toggle("%createWorldScreen.showCoordinates", session.getPreferencesCache().isPrefersShowCoordinates());
|
||||||
}
|
}
|
||||||
|
|
||||||
if (CooldownUtils.getDefaultShowCooldown() != CooldownUtils.CooldownType.DISABLED) {
|
if (CooldownUtils.getDefaultShowCooldown() != CooldownUtils.CooldownType.DISABLED) {
|
||||||
@ -175,6 +175,10 @@ public class SettingsUtils {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private static String translateEntry(String key, String locale) {
|
private static String translateEntry(String key, String locale) {
|
||||||
|
if (key.startsWith("%")) {
|
||||||
|
// Bedrock will translate
|
||||||
|
return key;
|
||||||
|
}
|
||||||
if (key.startsWith("geyser.")) {
|
if (key.startsWith("geyser.")) {
|
||||||
return GeyserLocale.getPlayerLocaleString(key, locale);
|
return GeyserLocale.getPlayerLocaleString(key, locale);
|
||||||
}
|
}
|
||||||
|
Laden…
In neuem Issue referenzieren
Einen Benutzer sperren