Mirror von
https://github.com/GeyserMC/Geyser.git
synchronisiert 2024-12-26 00:00:41 +01:00
Merge remote-tracking branch 'origin/master' into floodgate-2.0
# Conflicts: # connector/src/main/java/org/geysermc/connector/GeyserConnector.java # connector/src/main/java/org/geysermc/connector/network/translators/java/JavaJoinGameTranslator.java
Dieser Commit ist enthalten in:
Commit
b8f398aa3c
2
.github/FUNDING.yml
vendored
2
.github/FUNDING.yml
vendored
@ -1,7 +1,7 @@
|
||||
# These are supported funding model platforms
|
||||
|
||||
github: # Replace with up to 4 GitHub Sponsors-enabled usernames e.g., [user1, user2]
|
||||
patreon: GeyserMC
|
||||
patreon: #GeyserMC # Disabled currently
|
||||
open_collective: # Replace with a single Open Collective username
|
||||
ko_fi: # Replace with a single Ko-fi username
|
||||
tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel
|
||||
|
1
Jenkinsfile
vendored
1
Jenkinsfile
vendored
@ -24,6 +24,7 @@ pipeline {
|
||||
when {
|
||||
branch "master"
|
||||
}
|
||||
|
||||
steps {
|
||||
sh 'mvn javadoc:jar source:jar deploy -DskipTests'
|
||||
}
|
||||
|
@ -18,7 +18,7 @@ The ultimate goal of this project is to allow Minecraft: Bedrock Edition users t
|
||||
|
||||
Special thanks to the DragonProxy project for being a trailblazer in protocol translation and for all the team members who have now joined us here!
|
||||
|
||||
### Currently supporting Minecraft Bedrock v1.16.x and Minecraft Java v1.16.3.
|
||||
### Currently supporting Minecraft Bedrock v1.16.100 and Minecraft Java v1.16.4.
|
||||
|
||||
## Setting Up
|
||||
Take a look [here](https://github.com/GeyserMC/Geyser/wiki#Setup) for how to set up Geyser.
|
||||
|
@ -6,15 +6,15 @@
|
||||
<parent>
|
||||
<groupId>org.geysermc</groupId>
|
||||
<artifactId>bootstrap-parent</artifactId>
|
||||
<version>1.1.0</version>
|
||||
<relativePath>../</relativePath>
|
||||
<version>1.2.0-SNAPSHOT</version>
|
||||
</parent>
|
||||
<artifactId>bootstrap-bungeecord</artifactId>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.geysermc</groupId>
|
||||
<artifactId>connector</artifactId>
|
||||
<version>1.1.0</version>
|
||||
<version>1.2.0-SNAPSHOT</version>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
|
@ -27,10 +27,10 @@ package org.geysermc.platform.bungeecord;
|
||||
|
||||
import net.md_5.bungee.api.config.ListenerInfo;
|
||||
import net.md_5.bungee.api.plugin.Plugin;
|
||||
import org.geysermc.common.PlatformType;
|
||||
import org.geysermc.connector.GeyserConnector;
|
||||
import org.geysermc.connector.bootstrap.GeyserBootstrap;
|
||||
import org.geysermc.connector.command.CommandManager;
|
||||
import org.geysermc.connector.common.PlatformType;
|
||||
import org.geysermc.connector.configuration.GeyserConfiguration;
|
||||
import org.geysermc.connector.dump.BootstrapDumpInfo;
|
||||
import org.geysermc.connector.ping.GeyserLegacyPingPassthrough;
|
||||
|
@ -6,12 +6,11 @@
|
||||
<parent>
|
||||
<groupId>org.geysermc</groupId>
|
||||
<artifactId>geyser-parent</artifactId>
|
||||
<version>parent</version>
|
||||
<relativePath>../</relativePath>
|
||||
<version>1.2.0-SNAPSHOT</version>
|
||||
</parent>
|
||||
<artifactId>bootstrap-parent</artifactId>
|
||||
<version>1.1.0</version>
|
||||
<packaging>pom</packaging>
|
||||
|
||||
<repositories>
|
||||
<repository>
|
||||
<id>spigot-public</id>
|
||||
|
@ -6,15 +6,15 @@
|
||||
<parent>
|
||||
<groupId>org.geysermc</groupId>
|
||||
<artifactId>bootstrap-parent</artifactId>
|
||||
<version>1.1.0</version>
|
||||
<relativePath>../</relativePath>
|
||||
<version>1.2.0-SNAPSHOT</version>
|
||||
</parent>
|
||||
<artifactId>bootstrap-spigot</artifactId>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.geysermc</groupId>
|
||||
<artifactId>connector</artifactId>
|
||||
<version>1.1.0</version>
|
||||
<version>1.2.0-SNAPSHOT</version>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
@ -26,7 +26,7 @@
|
||||
<dependency>
|
||||
<groupId>us.myles</groupId>
|
||||
<artifactId>viaversion</artifactId>
|
||||
<version>3.1.1</version>
|
||||
<version>3.2.0</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
@ -27,10 +27,10 @@ package org.geysermc.platform.spigot;
|
||||
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.plugin.java.JavaPlugin;
|
||||
import org.geysermc.common.PlatformType;
|
||||
import org.geysermc.connector.GeyserConnector;
|
||||
import org.geysermc.connector.bootstrap.GeyserBootstrap;
|
||||
import org.geysermc.connector.command.CommandManager;
|
||||
import org.geysermc.connector.common.PlatformType;
|
||||
import org.geysermc.connector.configuration.GeyserConfiguration;
|
||||
import org.geysermc.connector.dump.BootstrapDumpInfo;
|
||||
import org.geysermc.connector.network.translators.world.WorldManager;
|
||||
@ -43,6 +43,7 @@ import org.geysermc.platform.spigot.command.GeyserSpigotCommandManager;
|
||||
import org.geysermc.platform.spigot.command.SpigotCommandSender;
|
||||
import org.geysermc.platform.spigot.world.GeyserSpigotBlockPlaceListener;
|
||||
import org.geysermc.platform.spigot.world.GeyserSpigotWorldManager;
|
||||
import us.myles.ViaVersion.api.Via;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
@ -121,6 +122,13 @@ public class GeyserSpigotPlugin extends JavaPlugin implements GeyserBootstrap {
|
||||
this.geyserCommandManager = new GeyserSpigotCommandManager(this, connector);
|
||||
|
||||
boolean isViaVersion = (Bukkit.getPluginManager().getPlugin("ViaVersion") != null);
|
||||
if (isViaVersion) {
|
||||
if (!isCompatible(Via.getAPI().getVersion().replace("-SNAPSHOT", ""), "3.2.0")) {
|
||||
geyserLogger.warning(LanguageUtils.getLocaleStringLog("geyser.bootstrap.viaversion.too_old",
|
||||
"https://ci.viaversion.com/job/ViaVersion/"));
|
||||
isViaVersion = false;
|
||||
}
|
||||
}
|
||||
// Used to determine if Block.getBlockData() is present.
|
||||
boolean isLegacy = !isCompatible(Bukkit.getServer().getVersion(), "1.13.0");
|
||||
if (isLegacy)
|
||||
|
@ -26,6 +26,7 @@
|
||||
package org.geysermc.platform.spigot.world;
|
||||
|
||||
import com.fasterxml.jackson.databind.JsonNode;
|
||||
import com.github.steveice10.mc.protocol.MinecraftConstants;
|
||||
import com.github.steveice10.mc.protocol.data.game.chunk.Chunk;
|
||||
import it.unimi.dsi.fastutil.ints.Int2IntMap;
|
||||
import it.unimi.dsi.fastutil.ints.Int2IntOpenHashMap;
|
||||
@ -41,14 +42,32 @@ import org.geysermc.connector.network.translators.world.block.BlockTranslator;
|
||||
import org.geysermc.connector.utils.FileUtils;
|
||||
import org.geysermc.connector.utils.GameRule;
|
||||
import org.geysermc.connector.utils.LanguageUtils;
|
||||
import us.myles.ViaVersion.protocols.protocol1_13_1to1_13.Protocol1_13_1To1_13;
|
||||
import us.myles.ViaVersion.protocols.protocol1_16_2to1_16_1.data.MappingData;
|
||||
import us.myles.ViaVersion.api.Pair;
|
||||
import us.myles.ViaVersion.api.Via;
|
||||
import us.myles.ViaVersion.api.data.MappingData;
|
||||
import us.myles.ViaVersion.api.minecraft.Position;
|
||||
import us.myles.ViaVersion.api.protocol.Protocol;
|
||||
import us.myles.ViaVersion.api.protocol.ProtocolRegistry;
|
||||
import us.myles.ViaVersion.api.protocol.ProtocolVersion;
|
||||
import us.myles.ViaVersion.protocols.protocol1_13to1_12_2.Protocol1_13To1_12_2;
|
||||
import us.myles.ViaVersion.protocols.protocol1_13to1_12_2.storage.BlockStorage;
|
||||
|
||||
import java.io.InputStream;
|
||||
import java.util.List;
|
||||
|
||||
public class GeyserSpigotWorldManager extends GeyserWorldManager {
|
||||
/**
|
||||
* The current client protocol version for ViaVersion usage.
|
||||
*/
|
||||
private static final int CLIENT_PROTOCOL_VERSION = MinecraftConstants.PROTOCOL_VERSION;
|
||||
|
||||
/**
|
||||
* Whether the server is pre-1.13.
|
||||
*/
|
||||
private final boolean isLegacy;
|
||||
/**
|
||||
* Whether the server is pre-1.16 and therefore does not support 3D biomes on an API level guaranteed.
|
||||
*/
|
||||
private final boolean use3dBiomes;
|
||||
/**
|
||||
* You need ViaVersion to connect to an older server with Geyser.
|
||||
@ -83,8 +102,9 @@ public class GeyserSpigotWorldManager extends GeyserWorldManager {
|
||||
}
|
||||
// Only load in the biomes that are present in this version of Minecraft
|
||||
for (Biome enumBiome : Biome.values()) {
|
||||
if (biomes.has(enumBiome.toString())) {
|
||||
biomeToIdMap.put(enumBiome.ordinal(), biomes.get(enumBiome.toString()).intValue());
|
||||
JsonNode biome = biomes.get(enumBiome.toString());
|
||||
if (biome != null) {
|
||||
biomeToIdMap.put(enumBiome.ordinal(), biome.intValue());
|
||||
} else {
|
||||
GeyserConnector.getInstance().getLogger().debug("No biome mapping found for " + enumBiome.toString() +
|
||||
", defaulting to 0");
|
||||
@ -99,7 +119,7 @@ public class GeyserSpigotWorldManager extends GeyserWorldManager {
|
||||
if ((this.isLegacy && !this.isViaVersion)
|
||||
|| session.getPlayerEntity() == null
|
||||
|| (bukkitPlayer = Bukkit.getPlayer(session.getPlayerEntity().getUsername())) == null) {
|
||||
return BlockTranslator.AIR;
|
||||
return BlockTranslator.JAVA_AIR_ID;
|
||||
}
|
||||
World world = bukkitPlayer.getWorld();
|
||||
if (isLegacy) {
|
||||
@ -111,29 +131,39 @@ public class GeyserSpigotWorldManager extends GeyserWorldManager {
|
||||
|
||||
public static int getLegacyBlock(GeyserSession session, int x, int y, int z, boolean isViaVersion) {
|
||||
if (isViaVersion) {
|
||||
return getLegacyBlock(Bukkit.getPlayer(session.getPlayerEntity().getUsername()).getWorld(), x, y, z, true);
|
||||
Player bukkitPlayer = Bukkit.getPlayer(session.getPlayerEntity().getUsername());
|
||||
// Get block entity storage
|
||||
BlockStorage storage = Via.getManager().getConnection(bukkitPlayer.getUniqueId()).get(BlockStorage.class);
|
||||
return getLegacyBlock(storage, bukkitPlayer.getWorld(), x, y, z);
|
||||
} else {
|
||||
return BlockTranslator.AIR;
|
||||
return BlockTranslator.JAVA_AIR_ID;
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings("deprecation")
|
||||
public static int getLegacyBlock(World world, int x, int y, int z, boolean isViaVersion) {
|
||||
if (isViaVersion) {
|
||||
public static int getLegacyBlock(BlockStorage storage, World world, int x, int y, int z) {
|
||||
Block block = world.getBlockAt(x, y, z);
|
||||
// Black magic that gets the old block state ID
|
||||
int oldBlockId = (block.getType().getId() << 4) | (block.getData() & 0xF);
|
||||
// Convert block state from old version -> 1.13 -> 1.13.1 -> 1.14 -> 1.15 -> 1.16 -> 1.16.2
|
||||
int thirteenBlockId = us.myles.ViaVersion.protocols.protocol1_13to1_12_2.data.MappingData.blockMappings.getNewId(oldBlockId);
|
||||
int thirteenPointOneBlockId = Protocol1_13_1To1_13.getNewBlockStateId(thirteenBlockId);
|
||||
int fourteenBlockId = us.myles.ViaVersion.protocols.protocol1_14to1_13_2.data.MappingData.blockStateMappings.getNewId(thirteenPointOneBlockId);
|
||||
int fifteenBlockId = us.myles.ViaVersion.protocols.protocol1_15to1_14_4.data.MappingData.blockStateMappings.getNewId(fourteenBlockId);
|
||||
int sixteenBlockId = us.myles.ViaVersion.protocols.protocol1_16to1_15_2.data.MappingData.blockStateMappings.getNewId(fifteenBlockId);
|
||||
return MappingData.blockStateMappings.getNewId(sixteenBlockId);
|
||||
} else {
|
||||
return BlockTranslator.AIR;
|
||||
int blockId = (block.getType().getId() << 4) | (block.getData() & 0xF);
|
||||
// Convert block state from old version (1.12.2) -> 1.13 -> 1.13.1 -> 1.14 -> 1.15 -> 1.16 -> 1.16.2
|
||||
blockId = ProtocolRegistry.getProtocol(Protocol1_13To1_12_2.class).getMappingData().getNewBlockId(blockId);
|
||||
List<Pair<Integer, Protocol>> protocolList = ProtocolRegistry.getProtocolPath(CLIENT_PROTOCOL_VERSION,
|
||||
ProtocolVersion.v1_13.getId());
|
||||
// Translate block entity differences - some information was stored in block tags and not block states
|
||||
if (storage.isWelcome(blockId)) { // No getOrDefault method
|
||||
BlockStorage.ReplacementData data = storage.get(new Position(x, (short) y, z));
|
||||
if (data != null && data.getReplacement() != -1) {
|
||||
blockId = data.getReplacement();
|
||||
}
|
||||
}
|
||||
for (int i = protocolList.size() - 1; i >= 0; i--) {
|
||||
MappingData mappingData = protocolList.get(i).getValue().getMappingData();
|
||||
if (mappingData != null) {
|
||||
blockId = mappingData.getNewBlockStateId(blockId);
|
||||
}
|
||||
}
|
||||
return blockId;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void getBlocksInSection(GeyserSession session, int x, int y, int z, Chunk chunk) {
|
||||
@ -145,10 +175,12 @@ public class GeyserSpigotWorldManager extends GeyserWorldManager {
|
||||
}
|
||||
World world = bukkitPlayer.getWorld();
|
||||
if (this.isLegacy) {
|
||||
// Get block entity storage
|
||||
BlockStorage storage = Via.getManager().getConnection(bukkitPlayer.getUniqueId()).get(BlockStorage.class);
|
||||
for (int blockY = 0; blockY < 16; blockY++) { // Cache-friendly iteration order
|
||||
for (int blockZ = 0; blockZ < 16; blockZ++) {
|
||||
for (int blockX = 0; blockX < 16; blockX++) {
|
||||
chunk.set(blockX, blockY, blockZ, getLegacyBlock(world, (x << 4) + blockX, (y << 4) + blockY, (z << 4) + blockZ, true));
|
||||
chunk.set(blockX, blockY, blockZ, getLegacyBlock(storage, world, (x << 4) + blockX, (y << 4) + blockY, (z << 4) + blockZ));
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -158,7 +190,7 @@ public class GeyserSpigotWorldManager extends GeyserWorldManager {
|
||||
for (int blockZ = 0; blockZ < 16; blockZ++) {
|
||||
for (int blockX = 0; blockX < 16; blockX++) {
|
||||
Block block = world.getBlockAt((x << 4) + blockX, (y << 4) + blockY, (z << 4) + blockZ);
|
||||
int id = BlockTranslator.getJavaIdBlockMap().getOrDefault(block.getBlockData().getAsString(), 0);
|
||||
int id = BlockTranslator.getJavaIdBlockMap().getOrDefault(block.getBlockData().getAsString(), BlockTranslator.JAVA_AIR_ID);
|
||||
chunk.set(blockX, blockY, blockZ, id);
|
||||
}
|
||||
}
|
||||
|
@ -6,15 +6,15 @@
|
||||
<parent>
|
||||
<groupId>org.geysermc</groupId>
|
||||
<artifactId>bootstrap-parent</artifactId>
|
||||
<version>1.1.0</version>
|
||||
<relativePath>../</relativePath>
|
||||
<version>1.2.0-SNAPSHOT</version>
|
||||
</parent>
|
||||
<artifactId>bootstrap-sponge</artifactId>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.geysermc</groupId>
|
||||
<artifactId>connector</artifactId>
|
||||
<version>1.1.0</version>
|
||||
<version>1.2.0-SNAPSHOT</version>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
|
@ -26,10 +26,10 @@
|
||||
package org.geysermc.platform.sponge;
|
||||
|
||||
import com.google.inject.Inject;
|
||||
import org.geysermc.common.PlatformType;
|
||||
import org.geysermc.connector.GeyserConnector;
|
||||
import org.geysermc.connector.bootstrap.GeyserBootstrap;
|
||||
import org.geysermc.connector.command.CommandManager;
|
||||
import org.geysermc.connector.common.PlatformType;
|
||||
import org.geysermc.connector.configuration.GeyserConfiguration;
|
||||
import org.geysermc.connector.dump.BootstrapDumpInfo;
|
||||
import org.geysermc.connector.ping.GeyserLegacyPingPassthrough;
|
||||
|
@ -6,15 +6,15 @@
|
||||
<parent>
|
||||
<groupId>org.geysermc</groupId>
|
||||
<artifactId>bootstrap-parent</artifactId>
|
||||
<version>1.1.0</version>
|
||||
<relativePath>../</relativePath>
|
||||
<version>1.2.0-SNAPSHOT</version>
|
||||
</parent>
|
||||
<artifactId>bootstrap-standalone</artifactId>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.geysermc</groupId>
|
||||
<artifactId>connector</artifactId>
|
||||
<version>1.1.0</version>
|
||||
<version>1.2.0-SNAPSHOT</version>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
|
@ -25,17 +25,23 @@
|
||||
|
||||
package org.geysermc.platform.standalone;
|
||||
|
||||
import com.fasterxml.jackson.databind.BeanDescription;
|
||||
import com.fasterxml.jackson.databind.JavaType;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import com.fasterxml.jackson.databind.introspect.AnnotatedField;
|
||||
import com.fasterxml.jackson.databind.introspect.BeanPropertyDefinition;
|
||||
import lombok.Getter;
|
||||
import net.minecrell.terminalconsole.TerminalConsoleAppender;
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.core.Appender;
|
||||
import org.apache.logging.log4j.core.Logger;
|
||||
import org.apache.logging.log4j.core.appender.ConsoleAppender;
|
||||
import org.geysermc.common.PlatformType;
|
||||
import org.geysermc.connector.GeyserConnector;
|
||||
import org.geysermc.connector.bootstrap.GeyserBootstrap;
|
||||
import org.geysermc.connector.command.CommandManager;
|
||||
import org.geysermc.connector.common.PlatformType;
|
||||
import org.geysermc.connector.configuration.GeyserConfiguration;
|
||||
import org.geysermc.connector.configuration.GeyserJacksonConfiguration;
|
||||
import org.geysermc.connector.dump.BootstrapDumpInfo;
|
||||
import org.geysermc.connector.ping.GeyserLegacyPingPassthrough;
|
||||
import org.geysermc.connector.ping.IGeyserPingPassthrough;
|
||||
@ -50,7 +56,8 @@ import java.lang.reflect.Method;
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.Paths;
|
||||
import java.text.MessageFormat;
|
||||
import java.util.UUID;
|
||||
import java.util.*;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
public class GeyserStandaloneBootstrap implements GeyserBootstrap {
|
||||
|
||||
@ -67,6 +74,9 @@ public class GeyserStandaloneBootstrap implements GeyserBootstrap {
|
||||
|
||||
private GeyserConnector connector;
|
||||
|
||||
private static final ObjectMapper OBJECT_MAPPER = new ObjectMapper();
|
||||
|
||||
private static final Map<String, String> argsConfigKeys = new HashMap<>();
|
||||
|
||||
public static void main(String[] args) {
|
||||
GeyserStandaloneBootstrap bootstrap = new GeyserStandaloneBootstrap();
|
||||
@ -74,6 +84,8 @@ public class GeyserStandaloneBootstrap implements GeyserBootstrap {
|
||||
boolean useGuiOpts = bootstrap.useGui;
|
||||
String configFilenameOpt = bootstrap.configFilename;
|
||||
|
||||
List<BeanPropertyDefinition> availableProperties = getPOJOForClass(GeyserJacksonConfiguration.class);
|
||||
|
||||
for (int i = 0; i < args.length; i++) {
|
||||
// By default, standalone Geyser will check if it should open the GUI based on if the GUI is null
|
||||
// Optionally, you can force the use of a GUI or no GUI by specifying args
|
||||
@ -91,11 +103,11 @@ public class GeyserStandaloneBootstrap implements GeyserBootstrap {
|
||||
case "--config":
|
||||
case "-c":
|
||||
if (i >= args.length - 1) {
|
||||
System.err.println(MessageFormat.format(LanguageUtils.getLocaleStringLog("geyser.bootstrap.args.confignotspecified"), "-c"));
|
||||
System.err.println(MessageFormat.format(LanguageUtils.getLocaleStringLog("geyser.bootstrap.args.config_not_specified"), "-c"));
|
||||
return;
|
||||
}
|
||||
configFilenameOpt = args[i+1]; i++;
|
||||
System.out.println(MessageFormat.format(LanguageUtils.getLocaleStringLog("geyser.bootstrap.args.configspecified"), configFilenameOpt));
|
||||
System.out.println(MessageFormat.format(LanguageUtils.getLocaleStringLog("geyser.bootstrap.args.config_specified"), configFilenameOpt));
|
||||
break;
|
||||
case "--help":
|
||||
case "-h":
|
||||
@ -106,8 +118,43 @@ public class GeyserStandaloneBootstrap implements GeyserBootstrap {
|
||||
System.out.println(" --gui, --nogui " + LanguageUtils.getLocaleStringLog("geyser.bootstrap.args.gui"));
|
||||
return;
|
||||
default:
|
||||
String badArgMsg = LanguageUtils.getLocaleStringLog("geyser.bootstrap.args.unrecognised");
|
||||
System.err.println(MessageFormat.format(badArgMsg, arg));
|
||||
// We have likely added a config option argument
|
||||
if (arg.startsWith("--")) {
|
||||
// Split the argument by an =
|
||||
String[] argParts = arg.substring(2).split("=");
|
||||
if (argParts.length == 2) {
|
||||
// Split the config key by . to allow for nested options
|
||||
String[] configKeyParts = argParts[0].split("\\.");
|
||||
|
||||
// Loop the possible config options to check the passed key is valid
|
||||
boolean found = false;
|
||||
for (BeanPropertyDefinition property : availableProperties) {
|
||||
if (configKeyParts[0].equals(property.getName())) {
|
||||
if (configKeyParts.length > 1) {
|
||||
// Loop sub-section options to check the passed key is valid
|
||||
for (BeanPropertyDefinition subProperty : getPOJOForClass(property.getRawPrimaryType())) {
|
||||
if (configKeyParts[1].equals(subProperty.getName())) {
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
found = true;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Add the found key to the stored list for later usage
|
||||
if (found) {
|
||||
argsConfigKeys.put(argParts[0], argParts[1]);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
System.err.println(LanguageUtils.getLocaleStringLog("geyser.bootstrap.args.unrecognised", arg));
|
||||
return;
|
||||
}
|
||||
}
|
||||
@ -148,6 +195,9 @@ public class GeyserStandaloneBootstrap implements GeyserBootstrap {
|
||||
try {
|
||||
File configFile = FileUtils.fileOrCopiedFromResource(new File(configFilename), "config.yml", (x) -> x.replaceAll("generateduuid", UUID.randomUUID().toString()));
|
||||
geyserConfig = FileUtils.loadConfig(configFile, GeyserStandaloneConfiguration.class);
|
||||
|
||||
handleArgsConfigOptions();
|
||||
|
||||
if (this.geyserConfig.getRemote().getAddress().equalsIgnoreCase("auto")) {
|
||||
geyserConfig.setAutoconfiguredRemote(true); // Doesn't really need to be set but /shrug
|
||||
geyserConfig.getRemote().setAddress("127.0.0.1");
|
||||
@ -223,4 +273,99 @@ public class GeyserStandaloneBootstrap implements GeyserBootstrap {
|
||||
public BootstrapDumpInfo getDumpInfo() {
|
||||
return new GeyserStandaloneDumpInfo(this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the {@link BeanPropertyDefinition}s for the given class
|
||||
*
|
||||
* @param clazz The class to get the definitions for
|
||||
* @return A list of {@link BeanPropertyDefinition} for the given class
|
||||
*/
|
||||
public static List<BeanPropertyDefinition> getPOJOForClass(Class<?> clazz) {
|
||||
JavaType javaType = OBJECT_MAPPER.getTypeFactory().constructType(clazz);
|
||||
|
||||
// Introspect the given type
|
||||
BeanDescription beanDescription = OBJECT_MAPPER.getSerializationConfig().introspect(javaType);
|
||||
|
||||
// Find properties
|
||||
List<BeanPropertyDefinition> properties = beanDescription.findProperties();
|
||||
|
||||
// Get the ignored properties
|
||||
Set<String> ignoredProperties = OBJECT_MAPPER.getSerializationConfig().getAnnotationIntrospector()
|
||||
.findPropertyIgnorals(beanDescription.getClassInfo()).getIgnored();
|
||||
|
||||
// Filter properties removing the ignored ones
|
||||
return properties.stream()
|
||||
.filter(property -> !ignoredProperties.contains(property.getName()))
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
|
||||
/**
|
||||
* Set a POJO property value on an object
|
||||
*
|
||||
* @param property The {@link BeanPropertyDefinition} to set
|
||||
* @param parentObject The object to alter
|
||||
* @param value The new value of the property
|
||||
*/
|
||||
private static void setConfigOption(BeanPropertyDefinition property, Object parentObject, Object value) {
|
||||
Object parsedValue = value;
|
||||
|
||||
// Change the values type if needed
|
||||
if (int.class.equals(property.getRawPrimaryType())) {
|
||||
parsedValue = Integer.valueOf((String) parsedValue);
|
||||
} else if (boolean.class.equals(property.getRawPrimaryType())) {
|
||||
parsedValue = Boolean.valueOf((String) parsedValue);
|
||||
}
|
||||
|
||||
// Force the value to be set
|
||||
AnnotatedField field = property.getField();
|
||||
field.fixAccess(true);
|
||||
field.setValue(parentObject, parsedValue);
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the loaded {@link GeyserStandaloneConfiguration} with any values passed in the command line arguments
|
||||
*/
|
||||
private void handleArgsConfigOptions() {
|
||||
// Get the available properties from the class
|
||||
List<BeanPropertyDefinition> availableProperties = getPOJOForClass(GeyserJacksonConfiguration.class);
|
||||
|
||||
for (Map.Entry<String, String> configKey : argsConfigKeys.entrySet()) {
|
||||
String[] configKeyParts = configKey.getKey().split("\\.");
|
||||
|
||||
// Loop over the properties looking for any matches against the stored one from the argument
|
||||
for (BeanPropertyDefinition property : availableProperties) {
|
||||
if (configKeyParts[0].equals(property.getName())) {
|
||||
if (configKeyParts.length > 1) {
|
||||
// Loop through the sub property if the first part matches
|
||||
for (BeanPropertyDefinition subProperty : getPOJOForClass(property.getRawPrimaryType())) {
|
||||
if (configKeyParts[1].equals(subProperty.getName())) {
|
||||
geyserLogger.info(LanguageUtils.getLocaleStringLog("geyser.bootstrap.args.set_config_option", configKey.getKey(), configKey.getValue()));
|
||||
|
||||
// Set the sub property value on the config
|
||||
try {
|
||||
Object subConfig = property.getGetter().callOn(geyserConfig);
|
||||
setConfigOption(subProperty, subConfig, configKey.getValue());
|
||||
} catch (Exception e) {
|
||||
geyserLogger.error("Failed to set config option: " + property.getFullName());
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
geyserLogger.info(LanguageUtils.getLocaleStringLog("geyser.bootstrap.args.set_config_option", configKey.getKey(), configKey.getValue()));
|
||||
|
||||
// Set the property value on the config
|
||||
try {
|
||||
setConfigOption(property, geyserConfig, configKey.getValue());
|
||||
} catch (Exception e) {
|
||||
geyserLogger.error("Failed to set config option: " + property.getFullName());
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -6,21 +6,21 @@
|
||||
<parent>
|
||||
<groupId>org.geysermc</groupId>
|
||||
<artifactId>bootstrap-parent</artifactId>
|
||||
<version>1.1.0</version>
|
||||
<relativePath>../</relativePath>
|
||||
<version>1.2.0-SNAPSHOT</version>
|
||||
</parent>
|
||||
<artifactId>bootstrap-velocity</artifactId>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.geysermc</groupId>
|
||||
<artifactId>connector</artifactId>
|
||||
<version>1.1.0</version>
|
||||
<version>1.2.0-SNAPSHOT</version>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.velocitypowered</groupId>
|
||||
<artifactId>velocity-api</artifactId>
|
||||
<version>1.0.0-SNAPSHOT</version>
|
||||
<version>1.1.0</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
@ -33,9 +33,9 @@ import com.velocitypowered.api.event.proxy.ProxyShutdownEvent;
|
||||
import com.velocitypowered.api.plugin.Plugin;
|
||||
import com.velocitypowered.api.proxy.ProxyServer;
|
||||
import lombok.Getter;
|
||||
import org.geysermc.common.PlatformType;
|
||||
import org.geysermc.connector.GeyserConnector;
|
||||
import org.geysermc.connector.bootstrap.GeyserBootstrap;
|
||||
import org.geysermc.connector.common.PlatformType;
|
||||
import org.geysermc.connector.configuration.GeyserConfiguration;
|
||||
import org.geysermc.connector.dump.BootstrapDumpInfo;
|
||||
import org.geysermc.connector.ping.GeyserLegacyPingPassthrough;
|
||||
@ -121,7 +121,7 @@ public class GeyserVelocityPlugin implements GeyserBootstrap {
|
||||
this.connector = GeyserConnector.start(PlatformType.VELOCITY, this);
|
||||
|
||||
this.geyserCommandManager = new GeyserVelocityCommandManager(connector);
|
||||
this.commandManager.register(new GeyserVelocityCommandExecutor(connector), "geyser");
|
||||
this.commandManager.register("geyser", new GeyserVelocityCommandExecutor(connector));
|
||||
if (geyserConfig.isLegacyPingPassthrough()) {
|
||||
this.geyserPingPassthrough = GeyserLegacyPingPassthrough.init(connector);
|
||||
} else {
|
||||
|
@ -6,11 +6,10 @@
|
||||
<parent>
|
||||
<groupId>org.geysermc</groupId>
|
||||
<artifactId>geyser-parent</artifactId>
|
||||
<version>parent</version>
|
||||
<relativePath>../</relativePath>
|
||||
<version>1.2.0-SNAPSHOT</version>
|
||||
</parent>
|
||||
<artifactId>common</artifactId>
|
||||
<version>1.1.0</version>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>com.google.code.gson</groupId>
|
||||
|
@ -23,7 +23,7 @@
|
||||
* @link https://github.com/GeyserMC/Geyser
|
||||
*/
|
||||
|
||||
package org.geysermc.connector.common;
|
||||
package org.geysermc.common;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Getter;
|
@ -6,16 +6,15 @@
|
||||
<parent>
|
||||
<groupId>org.geysermc</groupId>
|
||||
<artifactId>geyser-parent</artifactId>
|
||||
<version>parent</version>
|
||||
<relativePath>../</relativePath>
|
||||
<version>1.2.0-SNAPSHOT</version>
|
||||
</parent>
|
||||
<artifactId>connector</artifactId>
|
||||
<version>1.1.0</version>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.geysermc</groupId>
|
||||
<artifactId>common</artifactId>
|
||||
<version>1.1.0</version>
|
||||
<version>1.2.0-SNAPSHOT</version>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
@ -32,8 +31,8 @@
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.github.CloudburstMC.Protocol</groupId>
|
||||
<artifactId>bedrock-v408</artifactId>
|
||||
<version>02f46a8700</version>
|
||||
<artifactId>bedrock-v419</artifactId>
|
||||
<version>ce59d39118</version>
|
||||
<scope>compile</scope>
|
||||
<exclusions>
|
||||
<exclusion>
|
||||
@ -111,7 +110,7 @@
|
||||
<dependency>
|
||||
<groupId>com.github.steveice10</groupId>
|
||||
<artifactId>mcprotocollib</artifactId>
|
||||
<version>1b01b1ffef</version>
|
||||
<version>86e1901be5</version>
|
||||
<scope>compile</scope>
|
||||
<exclusions>
|
||||
<exclusion>
|
||||
@ -143,17 +142,23 @@
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>net.kyori</groupId>
|
||||
<groupId>com.github.kyoripowered.adventure</groupId>
|
||||
<artifactId>adventure-text-serializer-gson</artifactId>
|
||||
<version>4.1.1</version>
|
||||
<version>4d8a67d798</version>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>net.kyori</groupId>
|
||||
<groupId>com.github.kyoripowered.adventure</groupId>
|
||||
<artifactId>adventure-text-serializer-legacy</artifactId>
|
||||
<version>4.1.1</version>
|
||||
<version>0599048</version>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>junit</groupId>
|
||||
<artifactId>junit</artifactId>
|
||||
<version>4.13.1</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
<build>
|
||||
@ -283,6 +288,15 @@
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-surefire-plugin</artifactId>
|
||||
<version>2.22.0</version>
|
||||
<configuration>
|
||||
<!-- Force the right file encoding during unit testing -->
|
||||
<argLine>-Dfile.encoding=${project.build.sourceEncoding}</argLine>
|
||||
</configuration>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
</project>
|
||||
|
@ -32,10 +32,10 @@ import com.nukkitx.network.raknet.RakNetConstants;
|
||||
import com.nukkitx.protocol.bedrock.BedrockServer;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
import org.geysermc.common.PlatformType;
|
||||
import org.geysermc.connector.bootstrap.GeyserBootstrap;
|
||||
import org.geysermc.connector.command.CommandManager;
|
||||
import org.geysermc.connector.common.AuthType;
|
||||
import org.geysermc.connector.common.PlatformType;
|
||||
import org.geysermc.connector.configuration.GeyserConfiguration;
|
||||
import org.geysermc.connector.metrics.Metrics;
|
||||
import org.geysermc.connector.network.ConnectorServerEventHandler;
|
||||
@ -197,8 +197,7 @@ public class GeyserConnector {
|
||||
}
|
||||
}
|
||||
|
||||
if (config.isAboveBedrockNetherBuilding())
|
||||
DimensionUtils.changeBedrockNetherId(); // Apply End dimension ID workaround to Nether
|
||||
DimensionUtils.changeBedrockNetherId(config.isAboveBedrockNetherBuilding()); // Apply End dimension ID workaround to Nether
|
||||
|
||||
// https://github.com/GeyserMC/Geyser/issues/957
|
||||
RakNetConstants.MAXIMUM_MTU_SIZE = (short) config.getMtu();
|
||||
|
@ -25,7 +25,7 @@
|
||||
|
||||
package org.geysermc.connector.command.defaults;
|
||||
|
||||
import org.geysermc.connector.common.PlatformType;
|
||||
import org.geysermc.common.PlatformType;
|
||||
import org.geysermc.connector.GeyserConnector;
|
||||
import org.geysermc.connector.command.CommandSender;
|
||||
import org.geysermc.connector.command.GeyserCommand;
|
||||
|
@ -25,7 +25,7 @@
|
||||
|
||||
package org.geysermc.connector.command.defaults;
|
||||
|
||||
import org.geysermc.connector.common.PlatformType;
|
||||
import org.geysermc.common.PlatformType;
|
||||
import org.geysermc.connector.GeyserConnector;
|
||||
import org.geysermc.connector.command.CommandSender;
|
||||
import org.geysermc.connector.command.GeyserCommand;
|
||||
|
@ -81,6 +81,8 @@ public interface GeyserConfiguration {
|
||||
|
||||
boolean isForceResourcePacks();
|
||||
|
||||
boolean isXboxAchievementsEnabled();
|
||||
|
||||
int getCacheImages();
|
||||
|
||||
IMetricsInfo getMetrics();
|
||||
|
@ -107,6 +107,9 @@ public abstract class GeyserJacksonConfiguration implements GeyserConfiguration
|
||||
@JsonProperty("force-resource-packs")
|
||||
private boolean forceResourcePacks = true;
|
||||
|
||||
@JsonProperty("xbox-achievements-enabled")
|
||||
private boolean xboxAchievementsEnabled = false;
|
||||
|
||||
private MetricsInfo metrics = new MetricsInfo();
|
||||
|
||||
@Getter
|
||||
|
@ -27,7 +27,7 @@ package org.geysermc.connector.dump;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Getter;
|
||||
import org.geysermc.connector.common.PlatformType;
|
||||
import org.geysermc.common.PlatformType;
|
||||
import org.geysermc.connector.GeyserConnector;
|
||||
|
||||
import java.util.List;
|
||||
|
@ -26,13 +26,12 @@
|
||||
package org.geysermc.connector.entity;
|
||||
|
||||
import com.github.steveice10.mc.protocol.data.game.entity.metadata.EntityMetadata;
|
||||
import com.github.steveice10.mc.protocol.data.message.Message;
|
||||
import com.nukkitx.math.vector.Vector3f;
|
||||
import com.nukkitx.protocol.bedrock.data.entity.EntityData;
|
||||
import org.geysermc.connector.entity.type.EntityType;
|
||||
import org.geysermc.connector.network.session.GeyserSession;
|
||||
import org.geysermc.connector.network.translators.world.block.BlockTranslator;
|
||||
import org.geysermc.connector.utils.MessageUtils;
|
||||
import org.geysermc.connector.network.translators.chat.MessageTranslator;
|
||||
|
||||
public class CommandBlockMinecartEntity extends DefaultBlockMinecartEntity {
|
||||
|
||||
@ -51,7 +50,7 @@ public class CommandBlockMinecartEntity extends DefaultBlockMinecartEntity {
|
||||
metadata.put(EntityData.COMMAND_BLOCK_COMMAND, entityMetadata.getValue());
|
||||
}
|
||||
if (entityMetadata.getId() == 14) {
|
||||
metadata.put(EntityData.COMMAND_BLOCK_LAST_OUTPUT, MessageUtils.getBedrockMessage((Message) entityMetadata.getValue()));
|
||||
metadata.put(EntityData.COMMAND_BLOCK_LAST_OUTPUT, MessageTranslator.convertMessage(entityMetadata.getValue().toString()));
|
||||
}
|
||||
super.updateBedrockMetadata(entityMetadata, session);
|
||||
}
|
||||
|
@ -54,7 +54,7 @@ import org.geysermc.connector.network.session.GeyserSession;
|
||||
import org.geysermc.connector.network.translators.item.ItemRegistry;
|
||||
import org.geysermc.connector.utils.AttributeUtils;
|
||||
import org.geysermc.connector.utils.ChunkUtils;
|
||||
import org.geysermc.connector.utils.MessageUtils;
|
||||
import org.geysermc.connector.network.translators.chat.MessageTranslator;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
@ -67,8 +67,6 @@ public class Entity {
|
||||
protected long entityId;
|
||||
protected long geyserId;
|
||||
|
||||
protected String dimension;
|
||||
|
||||
protected Vector3f position;
|
||||
protected Vector3f motion;
|
||||
|
||||
@ -100,7 +98,6 @@ public class Entity {
|
||||
this.rotation = rotation;
|
||||
|
||||
this.valid = false;
|
||||
this.dimension = "minecraft:overworld";
|
||||
|
||||
setPosition(position);
|
||||
|
||||
@ -321,7 +318,7 @@ public class Entity {
|
||||
Message message = (Message) entityMetadata.getValue();
|
||||
if (message != null)
|
||||
// Always translate even if it's a TextMessage since there could be translatable parameters
|
||||
metadata.put(EntityData.NAMETAG, MessageUtils.getTranslatedBedrockMessage(message, session.getLocale(), true));
|
||||
metadata.put(EntityData.NAMETAG, MessageTranslator.convertMessage(message.toString(), session.getLocale()));
|
||||
}
|
||||
break;
|
||||
case 3: // is custom name visible
|
||||
@ -339,18 +336,6 @@ public class Entity {
|
||||
metadata.getFlags().setFlag(EntityFlag.SLEEPING, true);
|
||||
// Has to be a byte or it does not work
|
||||
metadata.put(EntityData.PLAYER_FLAGS, (byte) 2);
|
||||
if (entityId == session.getPlayerEntity().getEntityId()) {
|
||||
Vector3i lastInteractionPos = session.getLastInteractionPosition();
|
||||
metadata.put(EntityData.BED_POSITION, lastInteractionPos);
|
||||
if (session.getConnector().getConfig().isCacheChunks()) {
|
||||
int bed = session.getConnector().getWorldManager().getBlockAt(session, lastInteractionPos.getX(),
|
||||
lastInteractionPos.getY(), lastInteractionPos.getZ());
|
||||
// Bed has to be updated, or else player is floating in the air
|
||||
ChunkUtils.updateBlock(session, bed, lastInteractionPos);
|
||||
}
|
||||
} else {
|
||||
metadata.put(EntityData.BED_POSITION, Vector3i.from(position.getFloorX(), position.getFloorY() - 2, position.getFloorZ()));
|
||||
}
|
||||
metadata.put(EntityData.BOUNDING_BOX_WIDTH, 0.2f);
|
||||
metadata.put(EntityData.BOUNDING_BOX_HEIGHT, 0.2f);
|
||||
} else if (metadata.getFlags().getFlag(EntityFlag.SLEEPING)) {
|
||||
|
@ -69,7 +69,6 @@ public class ItemFrameEntity extends Entity {
|
||||
|
||||
public ItemFrameEntity(long entityId, long geyserId, EntityType entityType, Vector3f position, Vector3f motion, Vector3f rotation, HangingDirection direction) {
|
||||
super(entityId, geyserId, entityType, position, motion, rotation);
|
||||
NbtMapBuilder builder = NbtMap.builder();
|
||||
NbtMapBuilder blockBuilder = NbtMap.builder()
|
||||
.putString("name", "minecraft:frame")
|
||||
.putInt("version", BlockTranslator.getBlockStateVersion());
|
||||
@ -77,9 +76,7 @@ public class ItemFrameEntity extends Entity {
|
||||
.putInt("facing_direction", direction.ordinal())
|
||||
.putByte("item_frame_map_bit", (byte) 0)
|
||||
.build());
|
||||
builder.put("block", blockBuilder.build());
|
||||
builder.putShort("id", (short) 199);
|
||||
bedrockRuntimeId = BlockTranslator.getItemFrame(builder.build());
|
||||
bedrockRuntimeId = BlockTranslator.getItemFrame(blockBuilder.build());
|
||||
bedrockPosition = Vector3i.from(position.getFloorX(), position.getFloorY(), position.getFloorZ());
|
||||
}
|
||||
|
||||
@ -101,14 +98,12 @@ public class ItemFrameEntity extends Entity {
|
||||
ItemEntry itemEntry = ItemRegistry.getItem((ItemStack) entityMetadata.getValue());
|
||||
NbtMapBuilder builder = NbtMap.builder();
|
||||
|
||||
String blockName = ItemRegistry.getBedrockIdentifer(itemEntry);
|
||||
|
||||
builder.putByte("Count", (byte) itemData.getCount());
|
||||
if (itemData.getTag() != null) {
|
||||
builder.put("tag", itemData.getTag().toBuilder().build());
|
||||
}
|
||||
builder.putShort("Damage", itemData.getDamage());
|
||||
builder.putString("Name", blockName);
|
||||
builder.putString("Name", itemEntry.getBedrockIdentifier());
|
||||
NbtMapBuilder tag = getDefaultTag().toBuilder();
|
||||
tag.put("Item", builder.build());
|
||||
tag.putFloat("ItemDropChance", 1.0f);
|
||||
@ -141,7 +136,7 @@ public class ItemFrameEntity extends Entity {
|
||||
UpdateBlockPacket updateBlockPacket = new UpdateBlockPacket();
|
||||
updateBlockPacket.setDataLayer(0);
|
||||
updateBlockPacket.setBlockPosition(bedrockPosition);
|
||||
updateBlockPacket.setRuntimeId(0);
|
||||
updateBlockPacket.setRuntimeId(BlockTranslator.BEDROCK_AIR_ID);
|
||||
updateBlockPacket.getFlags().add(UpdateBlockPacket.Flag.PRIORITY);
|
||||
updateBlockPacket.getFlags().add(UpdateBlockPacket.Flag.NETWORK);
|
||||
updateBlockPacket.getFlags().add(UpdateBlockPacket.Flag.NEIGHBORS);
|
||||
@ -196,18 +191,6 @@ public class ItemFrameEntity extends Entity {
|
||||
return session.getItemFrameCache().getOrDefault(position, -1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines if the position contains an item frame.
|
||||
* Does largely the same thing as getItemFrameEntityId, but for speed purposes is implemented separately,
|
||||
* since every block destroy packet has to check for an item frame.
|
||||
* @param position position of block.
|
||||
* @param session GeyserSession.
|
||||
* @return true if position contains item frame, false if not.
|
||||
*/
|
||||
public static boolean positionContainsItemFrame(GeyserSession session, Vector3i position) {
|
||||
return session.getItemFrameCache().containsKey(position);
|
||||
}
|
||||
|
||||
/**
|
||||
* Force-remove from the position-to-ID map so it doesn't cause conflicts.
|
||||
* @param session GeyserSession.
|
||||
|
@ -27,10 +27,24 @@ package org.geysermc.connector.entity;
|
||||
|
||||
import com.nukkitx.math.vector.Vector3f;
|
||||
import org.geysermc.connector.entity.type.EntityType;
|
||||
import org.geysermc.connector.network.session.GeyserSession;
|
||||
|
||||
public class ItemedFireballEntity extends Entity {
|
||||
public class ItemedFireballEntity extends ThrowableEntity {
|
||||
private final Vector3f acceleration;
|
||||
|
||||
public ItemedFireballEntity(long entityId, long geyserId, EntityType entityType, Vector3f position, Vector3f motion, Vector3f rotation) {
|
||||
super(entityId, geyserId, entityType, position, motion, rotation);
|
||||
super(entityId, geyserId, entityType, position, Vector3f.ZERO, rotation);
|
||||
acceleration = motion;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void updatePosition(GeyserSession session) {
|
||||
position = position.add(motion);
|
||||
// TODO: While this reduces latency in position updating (needed for better fireball reflecting),
|
||||
// TODO: movement is incredibly stiff. See if the MoveEntityDeltaPacket in 1.16.100 fixes this, and if not,
|
||||
// TODO: only use this laggy movement for fireballs that be reflected
|
||||
moveAbsoluteImmediate(session, position, rotation, false, true);
|
||||
float drag = getDrag(session);
|
||||
motion = motion.add(acceleration).mul(drag);
|
||||
}
|
||||
}
|
||||
|
@ -26,7 +26,9 @@
|
||||
package org.geysermc.connector.entity;
|
||||
|
||||
import com.github.steveice10.mc.protocol.data.game.entity.metadata.EntityMetadata;
|
||||
import com.github.steveice10.mc.protocol.data.game.entity.metadata.Position;
|
||||
import com.nukkitx.math.vector.Vector3f;
|
||||
import com.nukkitx.math.vector.Vector3i;
|
||||
import com.nukkitx.protocol.bedrock.data.AttributeData;
|
||||
import com.nukkitx.protocol.bedrock.data.entity.EntityData;
|
||||
import com.nukkitx.protocol.bedrock.data.entity.EntityFlag;
|
||||
@ -42,6 +44,7 @@ import org.geysermc.connector.entity.type.EntityType;
|
||||
import org.geysermc.connector.network.session.GeyserSession;
|
||||
import org.geysermc.connector.network.translators.item.ItemRegistry;
|
||||
import org.geysermc.connector.utils.AttributeUtils;
|
||||
import org.geysermc.connector.utils.ChunkUtils;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
@ -84,6 +87,17 @@ public class LivingEntity extends Entity {
|
||||
case 10:
|
||||
metadata.put(EntityData.EFFECT_AMBIENT, (byte) ((boolean) entityMetadata.getValue() ? 1 : 0));
|
||||
break;
|
||||
case 13: // Bed Position
|
||||
Position bedPosition = (Position) entityMetadata.getValue();
|
||||
if (bedPosition != null) {
|
||||
metadata.put(EntityData.BED_POSITION, Vector3i.from(bedPosition.getX(), bedPosition.getY(), bedPosition.getZ()));
|
||||
if (session.getConnector().getConfig().isCacheChunks()) {
|
||||
int bed = session.getConnector().getWorldManager().getBlockAt(session, bedPosition);
|
||||
// Bed has to be updated, or else player is floating in the air
|
||||
ChunkUtils.updateBlock(session, bed, bedPosition);
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
super.updateBedrockMetadata(entityMetadata, session);
|
||||
|
@ -27,14 +27,15 @@ package org.geysermc.connector.entity;
|
||||
|
||||
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.scoreboard.NameTagVisibility;
|
||||
import com.github.steveice10.mc.protocol.data.message.TextMessage;
|
||||
import com.github.steveice10.opennbt.tag.builtin.CompoundTag;
|
||||
import com.nukkitx.math.vector.Vector3f;
|
||||
import com.nukkitx.math.vector.Vector3i;
|
||||
import com.nukkitx.protocol.bedrock.data.AttributeData;
|
||||
import com.nukkitx.protocol.bedrock.data.PlayerPermission;
|
||||
import com.nukkitx.protocol.bedrock.data.command.CommandPermission;
|
||||
import com.nukkitx.protocol.bedrock.data.entity.EntityData;
|
||||
import com.nukkitx.protocol.bedrock.data.entity.EntityFlag;
|
||||
import com.nukkitx.protocol.bedrock.data.entity.EntityLinkData;
|
||||
import com.nukkitx.protocol.bedrock.packet.AddPlayerPacket;
|
||||
import com.nukkitx.protocol.bedrock.packet.MovePlayerPacket;
|
||||
@ -50,7 +51,7 @@ import org.geysermc.connector.network.session.GeyserSession;
|
||||
import org.geysermc.connector.network.session.cache.EntityEffectCache;
|
||||
import org.geysermc.connector.scoreboard.Team;
|
||||
import org.geysermc.connector.utils.AttributeUtils;
|
||||
import org.geysermc.connector.utils.MessageUtils;
|
||||
import org.geysermc.connector.network.translators.chat.MessageTranslator;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
@ -168,6 +169,17 @@ public class PlayerEntity extends LivingEntity {
|
||||
movePlayerPacket.setRotation(getBedrockRotation());
|
||||
movePlayerPacket.setOnGround(isOnGround);
|
||||
movePlayerPacket.setMode(MovePlayerPacket.Mode.NORMAL);
|
||||
// If the player is moved while sleeping, we have to adjust their y, so it appears
|
||||
// correctly on Bedrock. This fixes GSit's lay.
|
||||
if (metadata.getFlags().getFlag(EntityFlag.SLEEPING)) {
|
||||
Vector3i bedPosition = metadata.getPos(EntityData.BED_POSITION);
|
||||
if (bedPosition != null && (bedPosition.getY() == 0 || bedPosition.distanceSquared(position.toInt()) > 4)) {
|
||||
// Force the player movement by using a teleport
|
||||
movePlayerPacket.setPosition(Vector3f.from(position.getX(), position.getY() - entityType.getOffset() + 0.2f, position.getZ()));
|
||||
movePlayerPacket.setMode(MovePlayerPacket.Mode.TELEPORT);
|
||||
movePlayerPacket.setTeleportationCause(MovePlayerPacket.TeleportationCause.UNKNOWN);
|
||||
}
|
||||
}
|
||||
session.sendUpstreamPacket(movePlayerPacket);
|
||||
if (leftParrot != null) {
|
||||
leftParrot.moveRelative(session, relX, relY, relZ, rotation, true);
|
||||
@ -231,22 +243,16 @@ public class PlayerEntity extends LivingEntity {
|
||||
String username = this.username;
|
||||
TextMessage name = (TextMessage) entityMetadata.getValue();
|
||||
if (name != null) {
|
||||
username = MessageUtils.getBedrockMessage(name);
|
||||
username = MessageTranslator.convertMessage(name.toString());
|
||||
}
|
||||
Team team = session.getWorldCache().getScoreboard().getTeamFor(username);
|
||||
if (team != null) {
|
||||
// Cover different visibility settings
|
||||
if (team.getNameTagVisibility() == NameTagVisibility.NEVER) {
|
||||
metadata.put(EntityData.NAMETAG, "");
|
||||
} else if (team.getNameTagVisibility() == NameTagVisibility.HIDE_FOR_OTHER_TEAMS &&
|
||||
!team.getEntities().contains(session.getPlayerEntity().getUsername())) {
|
||||
metadata.put(EntityData.NAMETAG, "");
|
||||
} else if (team.getNameTagVisibility() == NameTagVisibility.HIDE_FOR_OWN_TEAM &&
|
||||
team.getEntities().contains(session.getPlayerEntity().getUsername())) {
|
||||
metadata.put(EntityData.NAMETAG, "");
|
||||
} else {
|
||||
metadata.put(EntityData.NAMETAG, team.getPrefix() + MessageUtils.toChatColor(team.getColor()) + username + team.getSuffix());
|
||||
String displayName = "";
|
||||
if (team.isVisibleFor(session.getPlayerEntity().getUsername())) {
|
||||
displayName = MessageTranslator.toChatColor(team.getColor()) + username;
|
||||
displayName = team.getCurrentData().getDisplayName(displayName);
|
||||
}
|
||||
metadata.put(EntityData.NAMETAG, displayName);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -31,14 +31,23 @@ import com.nukkitx.protocol.bedrock.data.entity.EntityFlag;
|
||||
import com.nukkitx.protocol.bedrock.packet.LevelEventPacket;
|
||||
import org.geysermc.connector.entity.type.EntityType;
|
||||
import org.geysermc.connector.network.session.GeyserSession;
|
||||
import org.geysermc.connector.network.translators.world.block.BlockTranslator;
|
||||
|
||||
import java.util.concurrent.ScheduledFuture;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
/**
|
||||
* Used as a class for any object-like entity that moves as a projectile
|
||||
*/
|
||||
public class ThrowableEntity extends Entity {
|
||||
|
||||
private Vector3f lastPosition;
|
||||
private ScheduledFuture<?> positionUpdater;
|
||||
/**
|
||||
* Updates the position for the Bedrock client.
|
||||
*
|
||||
* Java clients assume the next positions of moving items. Bedrock needs to be explicitly told positions
|
||||
*/
|
||||
protected ScheduledFuture<?> positionUpdater;
|
||||
|
||||
public ThrowableEntity(long entityId, long geyserId, EntityType entityType, Vector3f position, Vector3f motion, Vector3f rotation) {
|
||||
super(entityId, geyserId, entityType, position, motion, rotation);
|
||||
@ -49,20 +58,86 @@ public class ThrowableEntity extends Entity {
|
||||
public void spawnEntity(GeyserSession session) {
|
||||
super.spawnEntity(session);
|
||||
positionUpdater = session.getConnector().getGeneralThreadPool().scheduleAtFixedRate(() -> {
|
||||
super.moveRelative(session, motion.getX(), motion.getY(), motion.getZ(), rotation, onGround);
|
||||
|
||||
if (metadata.getFlags().getFlag(EntityFlag.HAS_GRAVITY)) {
|
||||
float gravity = 0.03f; // Snowball, Egg, and Ender Pearl
|
||||
if (entityType == EntityType.THROWN_POTION || entityType == EntityType.LINGERING_POTION) {
|
||||
gravity = 0.05f;
|
||||
} else if (entityType == EntityType.THROWN_EXP_BOTTLE) {
|
||||
gravity = 0.07f;
|
||||
}
|
||||
motion = motion.down(gravity);
|
||||
if (session.isClosed()) {
|
||||
positionUpdater.cancel(true);
|
||||
return;
|
||||
}
|
||||
updatePosition(session);
|
||||
}, 0, 50, TimeUnit.MILLISECONDS);
|
||||
}
|
||||
|
||||
protected void moveAbsoluteImmediate(GeyserSession session, Vector3f position, Vector3f rotation, boolean isOnGround, boolean teleported) {
|
||||
super.moveAbsolute(session, position, rotation, isOnGround, teleported);
|
||||
}
|
||||
|
||||
protected void updatePosition(GeyserSession session) {
|
||||
super.moveRelative(session, motion.getX(), motion.getY(), motion.getZ(), rotation, onGround);
|
||||
float drag = getDrag(session);
|
||||
float gravity = getGravity();
|
||||
motion = motion.mul(drag).down(gravity);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the gravity of this entity type. Used for applying gravity while the entity is in motion.
|
||||
*
|
||||
* @return the amount of gravity to apply to this entity while in motion.
|
||||
*/
|
||||
protected float getGravity() {
|
||||
if (metadata.getFlags().getFlag(EntityFlag.HAS_GRAVITY)) {
|
||||
switch (entityType) {
|
||||
case THROWN_POTION:
|
||||
case LINGERING_POTION:
|
||||
return 0.05f;
|
||||
case THROWN_EXP_BOTTLE:
|
||||
return 0.07f;
|
||||
case FIREBALL:
|
||||
return 0;
|
||||
case SNOWBALL:
|
||||
case THROWN_EGG:
|
||||
case THROWN_ENDERPEARL:
|
||||
return 0.03f;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param session the session of the Bedrock client.
|
||||
* @return the drag that should be multiplied to the entity's motion
|
||||
*/
|
||||
protected float getDrag(GeyserSession session) {
|
||||
if (isInWater(session)) {
|
||||
return 0.8f;
|
||||
} else {
|
||||
switch (entityType) {
|
||||
case THROWN_POTION:
|
||||
case LINGERING_POTION:
|
||||
case THROWN_EXP_BOTTLE:
|
||||
case SNOWBALL:
|
||||
case THROWN_EGG:
|
||||
case THROWN_ENDERPEARL:
|
||||
return 0.99f;
|
||||
case FIREBALL:
|
||||
case SMALL_FIREBALL:
|
||||
case DRAGON_FIREBALL:
|
||||
return 0.95f;
|
||||
}
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param session the session of the Bedrock client.
|
||||
* @return true if this entity is currently in water.
|
||||
*/
|
||||
protected boolean isInWater(GeyserSession session) {
|
||||
if (session.getConnector().getConfig().isCacheChunks()) {
|
||||
int block = session.getConnector().getWorldManager().getBlockAt(session, position.toInt());
|
||||
return block == BlockTranslator.BEDROCK_WATER_ID;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean despawnEntity(GeyserSession session) {
|
||||
positionUpdater.cancel(true);
|
||||
|
@ -0,0 +1,58 @@
|
||||
/*
|
||||
* Copyright (c) 2019-2020 GeyserMC. http://geysermc.org
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*
|
||||
* @author GeyserMC
|
||||
* @link https://github.com/GeyserMC/Geyser
|
||||
*/
|
||||
|
||||
package org.geysermc.connector.entity;
|
||||
|
||||
import com.github.steveice10.mc.protocol.data.game.entity.metadata.EntityMetadata;
|
||||
import com.nukkitx.math.vector.Vector3f;
|
||||
import org.geysermc.connector.entity.type.EntityType;
|
||||
import org.geysermc.connector.network.session.GeyserSession;
|
||||
|
||||
public class WitherSkullEntity extends ItemedFireballEntity {
|
||||
private boolean isCharged;
|
||||
|
||||
public WitherSkullEntity(long entityId, long geyserId, EntityType entityType, Vector3f position, Vector3f motion, Vector3f rotation) {
|
||||
super(entityId, geyserId, entityType, position, motion, rotation);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected float getDrag(GeyserSession session) {
|
||||
return isCharged ? 0.73f : super.getDrag(session);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateBedrockMetadata(EntityMetadata entityMetadata, GeyserSession session) {
|
||||
if (entityMetadata.getId() == 7) {
|
||||
boolean newIsCharged = (boolean) entityMetadata.getValue();
|
||||
if (newIsCharged != isCharged) {
|
||||
isCharged = newIsCharged;
|
||||
entityType = isCharged ? EntityType.WITHER_SKULL_DANGEROUS : EntityType.WITHER_SKULL;
|
||||
despawnEntity(session);
|
||||
spawnEntity(session);
|
||||
}
|
||||
}
|
||||
super.updateBedrockMetadata(entityMetadata, session);
|
||||
}
|
||||
}
|
@ -29,6 +29,7 @@ import com.github.steveice10.mc.protocol.data.game.entity.metadata.EntityMetadat
|
||||
import com.github.steveice10.mc.protocol.data.game.entity.metadata.MetadataType;
|
||||
import com.nukkitx.math.vector.Vector3f;
|
||||
import com.nukkitx.protocol.bedrock.data.entity.EntityData;
|
||||
import lombok.Getter;
|
||||
import org.geysermc.connector.entity.LivingEntity;
|
||||
import org.geysermc.connector.entity.type.EntityType;
|
||||
import org.geysermc.connector.network.session.GeyserSession;
|
||||
@ -36,6 +37,7 @@ import org.geysermc.connector.network.session.GeyserSession;
|
||||
public class ArmorStandEntity extends LivingEntity {
|
||||
|
||||
// These are used to store the state of the armour stand for use when handling invisibility
|
||||
@Getter
|
||||
private boolean isMarker = false;
|
||||
private boolean isInvisible = false;
|
||||
private boolean isSmall = false;
|
||||
@ -47,7 +49,7 @@ public class ArmorStandEntity extends LivingEntity {
|
||||
@Override
|
||||
public void moveAbsolute(GeyserSession session, Vector3f position, Vector3f rotation, boolean isOnGround, boolean teleported) {
|
||||
// Fake the height to be above where it is so the nametag appears in the right location for invisible non-marker armour stands
|
||||
if (!isMarker && isInvisible) {
|
||||
if (!isMarker && isInvisible && passengers.isEmpty()) {
|
||||
position = position.add(0d, entityType.getHeight() * (isSmall ? 0.55d : 1d), 0d);
|
||||
}
|
||||
|
||||
|
@ -0,0 +1,48 @@
|
||||
/*
|
||||
* Copyright (c) 2019-2020 GeyserMC. http://geysermc.org
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*
|
||||
* @author GeyserMC
|
||||
* @link https://github.com/GeyserMC/Geyser
|
||||
*/
|
||||
|
||||
package org.geysermc.connector.entity.living;
|
||||
|
||||
import com.github.steveice10.mc.protocol.data.game.entity.metadata.EntityMetadata;
|
||||
import com.nukkitx.math.vector.Vector3f;
|
||||
import com.nukkitx.protocol.bedrock.data.entity.EntityFlag;
|
||||
import org.geysermc.connector.entity.type.EntityType;
|
||||
import org.geysermc.connector.network.session.GeyserSession;
|
||||
|
||||
public class BatEntity extends AmbientEntity {
|
||||
|
||||
public BatEntity(long entityId, long geyserId, EntityType entityType, Vector3f position, Vector3f motion, Vector3f rotation) {
|
||||
super(entityId, geyserId, entityType, position, motion, rotation);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateBedrockMetadata(EntityMetadata entityMetadata, GeyserSession session) {
|
||||
if (entityMetadata.getId() == 15) {
|
||||
byte xd = (byte) entityMetadata.getValue();
|
||||
metadata.getFlags().setFlag(EntityFlag.RESTING, (xd & 0x01) == 0x01);
|
||||
}
|
||||
super.updateBedrockMetadata(entityMetadata, session);
|
||||
}
|
||||
}
|
@ -0,0 +1,49 @@
|
||||
/*
|
||||
* Copyright (c) 2019-2020 GeyserMC. http://geysermc.org
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*
|
||||
* @author GeyserMC
|
||||
* @link https://github.com/GeyserMC/Geyser
|
||||
*/
|
||||
|
||||
package org.geysermc.connector.entity.living;
|
||||
|
||||
import com.github.steveice10.mc.protocol.data.game.entity.metadata.EntityMetadata;
|
||||
import com.nukkitx.math.vector.Vector3f;
|
||||
import com.nukkitx.protocol.bedrock.data.entity.EntityFlag;
|
||||
import org.geysermc.connector.entity.type.EntityType;
|
||||
import org.geysermc.connector.network.session.GeyserSession;
|
||||
|
||||
public class SnowGolemEntity extends GolemEntity {
|
||||
|
||||
public SnowGolemEntity(long entityId, long geyserId, EntityType entityType, Vector3f position, Vector3f motion, Vector3f rotation) {
|
||||
super(entityId, geyserId, entityType, position, motion, rotation);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateBedrockMetadata(EntityMetadata entityMetadata, GeyserSession session) {
|
||||
if (entityMetadata.getId() == 15) {
|
||||
byte xd = (byte) entityMetadata.getValue();
|
||||
// Handle the visibility of the pumpkin
|
||||
metadata.getFlags().setFlag(EntityFlag.SHEARED, (xd & 0x10) != 0x10);
|
||||
}
|
||||
super.updateBedrockMetadata(entityMetadata, session);
|
||||
}
|
||||
}
|
@ -27,7 +27,10 @@ package org.geysermc.connector.entity.living.animal;
|
||||
|
||||
import com.github.steveice10.mc.protocol.data.game.entity.metadata.EntityMetadata;
|
||||
import com.nukkitx.math.vector.Vector3f;
|
||||
import com.nukkitx.protocol.bedrock.data.entity.EntityData;
|
||||
import com.nukkitx.protocol.bedrock.data.entity.EntityEventType;
|
||||
import com.nukkitx.protocol.bedrock.data.entity.EntityFlag;
|
||||
import com.nukkitx.protocol.bedrock.packet.EntityEventPacket;
|
||||
import org.geysermc.connector.entity.type.EntityType;
|
||||
import org.geysermc.connector.network.session.GeyserSession;
|
||||
|
||||
@ -41,10 +44,23 @@ public class BeeEntity extends AnimalEntity {
|
||||
public void updateBedrockMetadata(EntityMetadata entityMetadata, GeyserSession session) {
|
||||
if (entityMetadata.getId() == 16) {
|
||||
byte xd = (byte) entityMetadata.getValue();
|
||||
metadata.getFlags().setFlag(EntityFlag.ANGRY, (xd & 0x02) == 0x02);
|
||||
// Bee is performing sting attack; trigger animation
|
||||
if ((xd & 0x02) == 0x02) {
|
||||
EntityEventPacket packet = new EntityEventPacket();
|
||||
packet.setRuntimeEntityId(geyserId);
|
||||
packet.setType(EntityEventType.ATTACK_START);
|
||||
packet.setData(0);
|
||||
session.sendUpstreamPacket(packet);
|
||||
}
|
||||
// If the bee has stung
|
||||
metadata.put(EntityData.MARK_VARIANT, (xd & 0x04) == 0x04 ? 1 : 0);
|
||||
// If the bee has nectar or not
|
||||
metadata.getFlags().setFlag(EntityFlag.POWERED, (xd & 0x08) == 0x08);
|
||||
}
|
||||
if (entityMetadata.getId() == 17) {
|
||||
// Converting "anger time" to a boolean
|
||||
metadata.getFlags().setFlag(EntityFlag.ANGRY, (int) entityMetadata.getValue() > 0);
|
||||
}
|
||||
super.updateBedrockMetadata(entityMetadata, session);
|
||||
}
|
||||
}
|
||||
|
@ -41,12 +41,13 @@ public class FoxEntity extends AnimalEntity {
|
||||
@Override
|
||||
public void updateBedrockMetadata(EntityMetadata entityMetadata, GeyserSession session) {
|
||||
if (entityMetadata.getId() == 16) {
|
||||
metadata.put(EntityData.VARIANT, (int) entityMetadata.getValue());
|
||||
metadata.put(EntityData.VARIANT, entityMetadata.getValue());
|
||||
}
|
||||
if (entityMetadata.getId() == 17) {
|
||||
byte xd = (byte) entityMetadata.getValue();
|
||||
metadata.getFlags().setFlag(EntityFlag.SITTING, (xd & 0x01) == 0x01);
|
||||
metadata.getFlags().setFlag(EntityFlag.SNEAKING, (xd & 0x04) == 0x04);
|
||||
metadata.getFlags().setFlag(EntityFlag.INTERESTED, (xd & 0x08) == 0x08);
|
||||
metadata.getFlags().setFlag(EntityFlag.SLEEPING, (xd & 0x20) == 0x20);
|
||||
}
|
||||
super.updateBedrockMetadata(entityMetadata, session);
|
||||
|
@ -0,0 +1,50 @@
|
||||
/*
|
||||
* Copyright (c) 2019-2020 GeyserMC. http://geysermc.org
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*
|
||||
* @author GeyserMC
|
||||
* @link https://github.com/GeyserMC/Geyser
|
||||
*/
|
||||
|
||||
package org.geysermc.connector.entity.living.animal;
|
||||
|
||||
import com.github.steveice10.mc.protocol.data.game.entity.metadata.EntityMetadata;
|
||||
import com.nukkitx.math.vector.Vector3f;
|
||||
import com.nukkitx.protocol.bedrock.data.entity.EntityFlag;
|
||||
import org.geysermc.connector.entity.type.EntityType;
|
||||
import org.geysermc.connector.network.session.GeyserSession;
|
||||
import org.geysermc.connector.utils.DimensionUtils;
|
||||
|
||||
public class HoglinEntity extends AnimalEntity {
|
||||
|
||||
public HoglinEntity(long entityId, long geyserId, EntityType entityType, Vector3f position, Vector3f motion, Vector3f rotation) {
|
||||
super(entityId, geyserId, entityType, position, motion, rotation);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateBedrockMetadata(EntityMetadata entityMetadata, GeyserSession session) {
|
||||
if (entityMetadata.getId() == 16) {
|
||||
// Immune to zombification?
|
||||
// Apply shaking effect if not in the nether and zombification is possible
|
||||
metadata.getFlags().setFlag(EntityFlag.SHAKING, !((boolean) entityMetadata.getValue()) && !session.getDimension().equals(DimensionUtils.NETHER));
|
||||
}
|
||||
super.updateBedrockMetadata(entityMetadata, session);
|
||||
}
|
||||
}
|
@ -0,0 +1,47 @@
|
||||
/*
|
||||
* Copyright (c) 2019-2020 GeyserMC. http://geysermc.org
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*
|
||||
* @author GeyserMC
|
||||
* @link https://github.com/GeyserMC/Geyser
|
||||
*/
|
||||
|
||||
package org.geysermc.connector.entity.living.animal;
|
||||
|
||||
import com.github.steveice10.mc.protocol.data.game.entity.metadata.EntityMetadata;
|
||||
import com.nukkitx.math.vector.Vector3f;
|
||||
import com.nukkitx.protocol.bedrock.data.entity.EntityData;
|
||||
import org.geysermc.connector.entity.type.EntityType;
|
||||
import org.geysermc.connector.network.session.GeyserSession;
|
||||
|
||||
public class MooshroomEntity extends AnimalEntity {
|
||||
|
||||
public MooshroomEntity(long entityId, long geyserId, EntityType entityType, Vector3f position, Vector3f motion, Vector3f rotation) {
|
||||
super(entityId, geyserId, entityType, position, motion, rotation);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateBedrockMetadata(EntityMetadata entityMetadata, GeyserSession session) {
|
||||
if (entityMetadata.getId() == 16) {
|
||||
metadata.put(EntityData.VARIANT, entityMetadata.getValue().equals("brown") ? 1 : 0);
|
||||
}
|
||||
super.updateBedrockMetadata(entityMetadata, session);
|
||||
}
|
||||
}
|
@ -27,23 +27,75 @@ package org.geysermc.connector.entity.living.animal;
|
||||
|
||||
import com.github.steveice10.mc.protocol.data.game.entity.metadata.EntityMetadata;
|
||||
import com.nukkitx.math.vector.Vector3f;
|
||||
import com.nukkitx.protocol.bedrock.data.entity.EntityData;
|
||||
import com.nukkitx.protocol.bedrock.data.entity.EntityEventType;
|
||||
import com.nukkitx.protocol.bedrock.data.entity.EntityFlag;
|
||||
import com.nukkitx.protocol.bedrock.packet.EntityEventPacket;
|
||||
import org.geysermc.connector.entity.type.EntityType;
|
||||
import org.geysermc.connector.network.session.GeyserSession;
|
||||
import org.geysermc.connector.network.translators.item.ItemRegistry;
|
||||
|
||||
public class PandaEntity extends AnimalEntity {
|
||||
|
||||
private int mainGene;
|
||||
private int hiddenGene;
|
||||
|
||||
public PandaEntity(long entityId, long geyserId, EntityType entityType, Vector3f position, Vector3f motion, Vector3f rotation) {
|
||||
super(entityId, geyserId, entityType, position, motion, rotation);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateBedrockMetadata(EntityMetadata entityMetadata, GeyserSession session) {
|
||||
if (entityMetadata.getId() == 18) {
|
||||
metadata.getFlags().setFlag(EntityFlag.EATING, (int) entityMetadata.getValue() > 0);
|
||||
metadata.put(EntityData.EATING_COUNTER, entityMetadata.getValue());
|
||||
if ((int) entityMetadata.getValue() != 0) {
|
||||
// Particles and sound
|
||||
EntityEventPacket packet = new EntityEventPacket();
|
||||
packet.setRuntimeEntityId(geyserId);
|
||||
packet.setType(EntityEventType.EATING_ITEM);
|
||||
packet.setData(ItemRegistry.BAMBOO.getBedrockId() << 16);
|
||||
session.sendUpstreamPacket(packet);
|
||||
}
|
||||
}
|
||||
if (entityMetadata.getId() == 19) {
|
||||
mainGene = (int) (byte) entityMetadata.getValue();
|
||||
updateAppearance();
|
||||
}
|
||||
if (entityMetadata.getId() == 20) {
|
||||
hiddenGene = (int) (byte) entityMetadata.getValue();
|
||||
updateAppearance();
|
||||
}
|
||||
if (entityMetadata.getId() == 21) {
|
||||
byte xd = (byte) entityMetadata.getValue();
|
||||
metadata.getFlags().setFlag(EntityFlag.SNEEZING, (xd & 0x02) == 0x02);
|
||||
metadata.getFlags().setFlag(EntityFlag.EATING, (xd & 0x04) == 0x04);
|
||||
metadata.getFlags().setFlag(EntityFlag.ROLLING, (xd & 0x04) == 0x04);
|
||||
metadata.getFlags().setFlag(EntityFlag.SITTING, (xd & 0x08) == 0x08);
|
||||
// Required to put these both for sitting to actually show
|
||||
metadata.put(EntityData.SITTING_AMOUNT, (xd & 0x08) == 0x08 ? 1f : 0f);
|
||||
metadata.put(EntityData.SITTING_AMOUNT_PREVIOUS, (xd & 0x08) == 0x08 ? 1f : 0f);
|
||||
metadata.getFlags().setFlag(EntityFlag.LAYING_DOWN, (xd & 0x10) == 0x10);
|
||||
}
|
||||
super.updateBedrockMetadata(entityMetadata, session);
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the panda's appearance, and take into consideration the recessive brown and weak traits that only show up
|
||||
* when both main and hidden genes match
|
||||
*/
|
||||
private void updateAppearance() {
|
||||
if (mainGene == 4 || mainGene == 5) {
|
||||
// Main gene is a recessive trait
|
||||
if (mainGene == hiddenGene) {
|
||||
// Main and hidden genes match; this is what the panda looks like.
|
||||
metadata.put(EntityData.VARIANT, mainGene);
|
||||
} else {
|
||||
// Genes have no effect on appearance
|
||||
metadata.put(EntityData.VARIANT, 0);
|
||||
}
|
||||
} else {
|
||||
// No need to worry about hidden gene
|
||||
metadata.put(EntityData.VARIANT, mainGene);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -48,6 +48,15 @@ public class RabbitEntity extends AnimalEntity {
|
||||
metadata.put(EntityData.SCALE, .35f);
|
||||
metadata.getFlags().setFlag(EntityFlag.BABY, true);
|
||||
}
|
||||
} else if (entityMetadata.getId() == 16) {
|
||||
int variant = (int) entityMetadata.getValue();
|
||||
|
||||
// Change the killer bunny to display as white since it only exists on Java Edition
|
||||
if (variant == 99) {
|
||||
variant = 1;
|
||||
}
|
||||
|
||||
metadata.put(EntityData.VARIANT, variant);
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,49 @@
|
||||
/*
|
||||
* Copyright (c) 2019-2020 GeyserMC. http://geysermc.org
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*
|
||||
* @author GeyserMC
|
||||
* @link https://github.com/GeyserMC/Geyser
|
||||
*/
|
||||
|
||||
package org.geysermc.connector.entity.living.animal;
|
||||
|
||||
import com.github.steveice10.mc.protocol.data.game.entity.metadata.EntityMetadata;
|
||||
import com.nukkitx.math.vector.Vector3f;
|
||||
import com.nukkitx.protocol.bedrock.data.entity.EntityFlag;
|
||||
import org.geysermc.connector.entity.type.EntityType;
|
||||
import org.geysermc.connector.network.session.GeyserSession;
|
||||
|
||||
public class TurtleEntity extends AnimalEntity {
|
||||
|
||||
public TurtleEntity(long entityId, long geyserId, EntityType entityType, Vector3f position, Vector3f motion, Vector3f rotation) {
|
||||
super(entityId, geyserId, entityType, position, motion, rotation);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateBedrockMetadata(EntityMetadata entityMetadata, GeyserSession session) {
|
||||
if (entityMetadata.getId() == 17) {
|
||||
metadata.getFlags().setFlag(EntityFlag.IS_PREGNANT, (boolean) entityMetadata.getValue());
|
||||
} else if (entityMetadata.getId() == 18) {
|
||||
metadata.getFlags().setFlag(EntityFlag.LAYING_EGG, (boolean) entityMetadata.getValue());
|
||||
}
|
||||
super.updateBedrockMetadata(entityMetadata, session);
|
||||
}
|
||||
}
|
@ -27,10 +27,14 @@ package org.geysermc.connector.entity.living.animal.horse;
|
||||
|
||||
import com.github.steveice10.mc.protocol.data.game.entity.metadata.EntityMetadata;
|
||||
import com.nukkitx.math.vector.Vector3f;
|
||||
import com.nukkitx.protocol.bedrock.data.entity.EntityData;
|
||||
import com.nukkitx.protocol.bedrock.data.entity.EntityEventType;
|
||||
import com.nukkitx.protocol.bedrock.data.entity.EntityFlag;
|
||||
import com.nukkitx.protocol.bedrock.packet.EntityEventPacket;
|
||||
import org.geysermc.connector.entity.living.animal.AnimalEntity;
|
||||
import org.geysermc.connector.entity.type.EntityType;
|
||||
import org.geysermc.connector.network.session.GeyserSession;
|
||||
import org.geysermc.connector.network.translators.item.ItemRegistry;
|
||||
|
||||
public class AbstractHorseEntity extends AnimalEntity {
|
||||
|
||||
@ -47,6 +51,30 @@ public class AbstractHorseEntity extends AnimalEntity {
|
||||
metadata.getFlags().setFlag(EntityFlag.SADDLED, (xd & 0x04) == 0x04);
|
||||
metadata.getFlags().setFlag(EntityFlag.EATING, (xd & 0x10) == 0x10);
|
||||
metadata.getFlags().setFlag(EntityFlag.STANDING, (xd & 0x20) == 0x20);
|
||||
|
||||
// HorseFlags
|
||||
// Bred 0x10
|
||||
// Eating 0x20
|
||||
// Open mouth 0x80
|
||||
int horseFlags = 0x0;
|
||||
horseFlags = (xd & 0x40) == 0x40 ? horseFlags | 0x80 : horseFlags;
|
||||
|
||||
// Only set eating when we don't have mouth open so a player interaction doesn't trigger the eating animation
|
||||
horseFlags = (xd & 0x10) == 0x10 && (xd & 0x40) != 0x40 ? horseFlags | 0x20 : horseFlags;
|
||||
|
||||
// Set the flags into the display item
|
||||
metadata.put(EntityData.DISPLAY_ITEM, horseFlags);
|
||||
|
||||
// Send the eating particles
|
||||
// We use the wheat metadata as static particles since Java
|
||||
// doesn't send over what item was used to feed the horse
|
||||
if ((xd & 0x40) == 0x40) {
|
||||
EntityEventPacket entityEventPacket = new EntityEventPacket();
|
||||
entityEventPacket.setRuntimeEntityId(geyserId);
|
||||
entityEventPacket.setType(EntityEventType.EATING_ITEM);
|
||||
entityEventPacket.setData(ItemRegistry.WHEAT.getBedrockId() << 16);
|
||||
session.sendUpstreamPacket(entityEventPacket);
|
||||
}
|
||||
}
|
||||
|
||||
// Needed to control horses
|
||||
|
@ -28,7 +28,6 @@ package org.geysermc.connector.entity.living.animal.horse;
|
||||
import com.github.steveice10.mc.protocol.data.game.entity.metadata.EntityMetadata;
|
||||
import com.nukkitx.math.vector.Vector3f;
|
||||
import com.nukkitx.protocol.bedrock.data.entity.EntityData;
|
||||
import com.nukkitx.protocol.bedrock.data.entity.EntityFlag;
|
||||
import org.geysermc.connector.entity.type.EntityType;
|
||||
import org.geysermc.connector.network.session.GeyserSession;
|
||||
|
||||
@ -41,7 +40,7 @@ public class HorseEntity extends AbstractHorseEntity {
|
||||
@Override
|
||||
public void updateBedrockMetadata(EntityMetadata entityMetadata, GeyserSession session) {
|
||||
if (entityMetadata.getId() == 18) {
|
||||
metadata.put(EntityData.VARIANT, (int) entityMetadata.getValue());
|
||||
metadata.put(EntityData.VARIANT, entityMetadata.getValue());
|
||||
metadata.put(EntityData.MARK_VARIANT, (((int) entityMetadata.getValue()) >> 8) % 5);
|
||||
}
|
||||
super.updateBedrockMetadata(entityMetadata, session);
|
||||
|
@ -34,6 +34,8 @@ import org.geysermc.connector.network.session.GeyserSession;
|
||||
|
||||
public class CatEntity extends TameableEntity {
|
||||
|
||||
private byte collarColor;
|
||||
|
||||
public CatEntity(long entityId, long geyserId, EntityType entityType, Vector3f position, Vector3f motion, Vector3f rotation) {
|
||||
super(entityId, geyserId, entityType, position, motion, rotation);
|
||||
}
|
||||
@ -45,6 +47,13 @@ public class CatEntity extends TameableEntity {
|
||||
|
||||
@Override
|
||||
public void updateBedrockMetadata(EntityMetadata entityMetadata, GeyserSession session) {
|
||||
super.updateBedrockMetadata(entityMetadata, session);
|
||||
if (entityMetadata.getId() == 16) {
|
||||
// Update collar color if tamed
|
||||
if (metadata.getFlags().getFlag(EntityFlag.TAMED)) {
|
||||
metadata.put(EntityData.COLOR, collarColor);
|
||||
}
|
||||
}
|
||||
if (entityMetadata.getId() == 18) {
|
||||
// Different colors in Java and Bedrock for some reason
|
||||
int variantColor;
|
||||
@ -67,11 +76,11 @@ public class CatEntity extends TameableEntity {
|
||||
metadata.put(EntityData.VARIANT, variantColor);
|
||||
}
|
||||
if (entityMetadata.getId() == 21) {
|
||||
collarColor = (byte) (int) entityMetadata.getValue();
|
||||
// Needed or else wild cats are a red color
|
||||
if (metadata.getFlags().getFlag(EntityFlag.TAMED)) {
|
||||
metadata.put(EntityData.COLOR, (byte) (int) entityMetadata.getValue());
|
||||
metadata.put(EntityData.COLOR, collarColor);
|
||||
}
|
||||
}
|
||||
super.updateBedrockMetadata(entityMetadata, session);
|
||||
}
|
||||
}
|
||||
|
@ -29,10 +29,13 @@ import com.github.steveice10.mc.protocol.data.game.entity.metadata.EntityMetadat
|
||||
import com.nukkitx.math.vector.Vector3f;
|
||||
import com.nukkitx.protocol.bedrock.data.entity.EntityData;
|
||||
import com.nukkitx.protocol.bedrock.data.entity.EntityFlag;
|
||||
import org.geysermc.connector.entity.Entity;
|
||||
import org.geysermc.connector.entity.living.animal.AnimalEntity;
|
||||
import org.geysermc.connector.entity.type.EntityType;
|
||||
import org.geysermc.connector.network.session.GeyserSession;
|
||||
|
||||
import java.util.UUID;
|
||||
|
||||
public class TameableEntity extends AnimalEntity {
|
||||
|
||||
public TameableEntity(long entityId, long geyserId, EntityType entityType, Vector3f position, Vector3f motion, Vector3f rotation) {
|
||||
@ -46,11 +49,22 @@ public class TameableEntity extends AnimalEntity {
|
||||
metadata.getFlags().setFlag(EntityFlag.SITTING, (xd & 0x01) == 0x01);
|
||||
metadata.getFlags().setFlag(EntityFlag.ANGRY, (xd & 0x02) == 0x02);
|
||||
metadata.getFlags().setFlag(EntityFlag.TAMED, (xd & 0x04) == 0x04);
|
||||
// Must be set for wolf collar color to work
|
||||
// Extending it to all entities to prevent future bugs
|
||||
if (metadata.getFlags().getFlag(EntityFlag.TAMED)) {
|
||||
metadata.put(EntityData.OWNER_EID, session.getPlayerEntity().getGeyserId());
|
||||
} // Can't de-tame an entity so no resetting the owner ID
|
||||
}
|
||||
|
||||
// Note: Must be set for wolf collar color to work
|
||||
if (entityMetadata.getId() == 17) {
|
||||
if (entityMetadata.getValue() != null) {
|
||||
// Owner UUID of entity
|
||||
Entity entity = session.getEntityCache().getPlayerEntity((UUID) entityMetadata.getValue());
|
||||
// Used as both a check since the player isn't in the entity cache and a normal fallback
|
||||
if (entity == null) {
|
||||
entity = session.getPlayerEntity();
|
||||
}
|
||||
// Translate to entity ID
|
||||
metadata.put(EntityData.OWNER_EID, entity.getGeyserId());
|
||||
} else {
|
||||
metadata.put(EntityData.OWNER_EID, 0L); // Reset
|
||||
}
|
||||
}
|
||||
super.updateBedrockMetadata(entityMetadata, session);
|
||||
}
|
||||
|
@ -26,26 +26,32 @@
|
||||
package org.geysermc.connector.entity.living.merchant;
|
||||
|
||||
import com.github.steveice10.mc.protocol.data.game.entity.metadata.EntityMetadata;
|
||||
import com.github.steveice10.mc.protocol.data.game.entity.metadata.VillagerData;
|
||||
import com.github.steveice10.mc.protocol.data.game.entity.metadata.Position;
|
||||
import com.github.steveice10.mc.protocol.data.game.entity.metadata.VillagerData;
|
||||
import com.nukkitx.math.vector.Vector3f;
|
||||
import com.nukkitx.math.vector.Vector3i;
|
||||
import com.nukkitx.protocol.bedrock.data.entity.EntityData;
|
||||
import com.nukkitx.protocol.bedrock.data.entity.EntityFlag;
|
||||
import com.nukkitx.protocol.bedrock.data.entity.EntityFlags;
|
||||
import com.nukkitx.protocol.bedrock.packet.*;
|
||||
import com.nukkitx.protocol.bedrock.packet.MoveEntityAbsolutePacket;
|
||||
import it.unimi.dsi.fastutil.ints.Int2IntMap;
|
||||
import it.unimi.dsi.fastutil.ints.Int2IntOpenHashMap;
|
||||
import org.geysermc.connector.entity.type.EntityType;
|
||||
import org.geysermc.connector.network.session.GeyserSession;
|
||||
import org.geysermc.connector.network.translators.world.WorldManager;
|
||||
import org.geysermc.connector.network.translators.world.block.BlockTranslator;
|
||||
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
public class VillagerEntity extends AbstractMerchantEntity {
|
||||
|
||||
/**
|
||||
* A map of Java profession IDs to Bedrock IDs
|
||||
*/
|
||||
private static final Int2IntMap VILLAGER_VARIANTS = new Int2IntOpenHashMap();
|
||||
private static final Int2IntMap VILLAGER_REGIONS = new Int2IntOpenHashMap();
|
||||
/**
|
||||
* A map of all Java region IDs (plains, savanna...) to Bedrock
|
||||
*/
|
||||
public static final Int2IntMap VILLAGER_REGIONS = new Int2IntOpenHashMap();
|
||||
|
||||
static {
|
||||
// Java villager profession IDs -> Bedrock
|
||||
@ -99,9 +105,9 @@ public class VillagerEntity extends AbstractMerchantEntity {
|
||||
int bedId = 0;
|
||||
float bedPositionSubtractorW = 0;
|
||||
float bedPositionSubtractorN = 0;
|
||||
if (session.getConnector().getConfig().isCacheChunks()) {
|
||||
Position bedLocation = new Position((int) position.getFloorX(), (int) position.getFloorY(), (int) position.getFloorZ());
|
||||
bedId = session.getConnector().getWorldManager().getBlockAt(session, bedLocation);
|
||||
Vector3i bedPosition = metadata.getPos(EntityData.BED_POSITION);
|
||||
if (session.getConnector().getConfig().isCacheChunks() && bedPosition != null) {
|
||||
bedId = session.getConnector().getWorldManager().getBlockAt(session, bedPosition);
|
||||
}
|
||||
String bedRotationZ = BlockTranslator.getJavaIdBlockMap().inverse().get(bedId);
|
||||
setRotation(rotation);
|
||||
|
@ -1,11 +1,25 @@
|
||||
package org.geysermc.connector.entity.living.monster;
|
||||
|
||||
import com.github.steveice10.mc.protocol.data.game.entity.metadata.EntityMetadata;
|
||||
import com.nukkitx.math.vector.Vector3f;
|
||||
import com.nukkitx.protocol.bedrock.data.entity.EntityFlag;
|
||||
import org.geysermc.connector.entity.type.EntityType;
|
||||
import org.geysermc.connector.network.session.GeyserSession;
|
||||
import org.geysermc.connector.utils.DimensionUtils;
|
||||
|
||||
public class BasePiglinEntity extends MonsterEntity {
|
||||
|
||||
public BasePiglinEntity(long entityId, long geyserId, EntityType entityType, Vector3f position, Vector3f motion, Vector3f rotation) {
|
||||
super(entityId, geyserId, entityType, position, motion, rotation);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateBedrockMetadata(EntityMetadata entityMetadata, GeyserSession session) {
|
||||
if (entityMetadata.getId() == 15) {
|
||||
// Immune to zombification?
|
||||
// Apply shaking effect if not in the nether and zombification is possible
|
||||
metadata.getFlags().setFlag(EntityFlag.SHAKING, !((boolean) entityMetadata.getValue()) && !session.getDimension().equals(DimensionUtils.NETHER));
|
||||
}
|
||||
super.updateBedrockMetadata(entityMetadata, session);
|
||||
}
|
||||
}
|
@ -33,6 +33,12 @@ import org.geysermc.connector.network.session.GeyserSession;
|
||||
|
||||
public class CreeperEntity extends MonsterEntity {
|
||||
|
||||
/**
|
||||
* Whether the creeper has been ignited and is using ID 17.
|
||||
* In this instance we ignore ID 15 since it's sending us -1 which confuses poor Bedrock.
|
||||
*/
|
||||
private boolean ignitedByFlintAndSteel = false;
|
||||
|
||||
public CreeperEntity(long entityId, long geyserId, EntityType entityType, Vector3f position, Vector3f motion, Vector3f rotation) {
|
||||
super(entityId, geyserId, entityType, position, motion, rotation);
|
||||
}
|
||||
@ -40,13 +46,16 @@ public class CreeperEntity extends MonsterEntity {
|
||||
@Override
|
||||
public void updateBedrockMetadata(EntityMetadata entityMetadata, GeyserSession session) {
|
||||
if (entityMetadata.getId() == 15) {
|
||||
if (!ignitedByFlintAndSteel) {
|
||||
metadata.getFlags().setFlag(EntityFlag.IGNITED, (int) entityMetadata.getValue() == 1);
|
||||
}
|
||||
}
|
||||
if (entityMetadata.getId() == 16) {
|
||||
metadata.getFlags().setFlag(EntityFlag.POWERED, (boolean) entityMetadata.getValue());
|
||||
}
|
||||
if (entityMetadata.getId() == 17) {
|
||||
metadata.getFlags().setFlag(EntityFlag.IGNITED, (boolean) entityMetadata.getValue());
|
||||
ignitedByFlintAndSteel = (boolean) entityMetadata.getValue();
|
||||
metadata.getFlags().setFlag(EntityFlag.IGNITED, ignitedByFlintAndSteel);
|
||||
}
|
||||
|
||||
super.updateBedrockMetadata(entityMetadata, session);
|
||||
|
@ -0,0 +1,49 @@
|
||||
/*
|
||||
* Copyright (c) 2019-2020 GeyserMC. http://geysermc.org
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*
|
||||
* @author GeyserMC
|
||||
* @link https://github.com/GeyserMC/Geyser
|
||||
*/
|
||||
|
||||
package org.geysermc.connector.entity.living.monster;
|
||||
|
||||
import com.github.steveice10.mc.protocol.data.game.entity.metadata.EntityMetadata;
|
||||
import com.nukkitx.math.vector.Vector3f;
|
||||
import com.nukkitx.protocol.bedrock.data.entity.EntityData;
|
||||
import org.geysermc.connector.entity.living.FlyingEntity;
|
||||
import org.geysermc.connector.entity.type.EntityType;
|
||||
import org.geysermc.connector.network.session.GeyserSession;
|
||||
|
||||
public class GhastEntity extends FlyingEntity {
|
||||
|
||||
public GhastEntity(long entityId, long geyserId, EntityType entityType, Vector3f position, Vector3f motion, Vector3f rotation) {
|
||||
super(entityId, geyserId, entityType, position, motion, rotation);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateBedrockMetadata(EntityMetadata entityMetadata, GeyserSession session) {
|
||||
if (entityMetadata.getId() == 15) {
|
||||
// If the ghast is attacking
|
||||
metadata.put(EntityData.CHARGE_AMOUNT, (byte) ((boolean) entityMetadata.getValue() ? 1 : 0));
|
||||
}
|
||||
super.updateBedrockMetadata(entityMetadata, session);
|
||||
}
|
||||
}
|
@ -41,7 +41,7 @@ public class PiglinEntity extends BasePiglinEntity {
|
||||
|
||||
@Override
|
||||
public void updateBedrockMetadata(EntityMetadata entityMetadata, GeyserSession session) {
|
||||
if (entityMetadata.getId() == 15) {
|
||||
if (entityMetadata.getId() == 16) {
|
||||
boolean isBaby = (boolean) entityMetadata.getValue();
|
||||
if (isBaby) {
|
||||
metadata.put(EntityData.SCALE, .55f);
|
||||
|
@ -0,0 +1,50 @@
|
||||
/*
|
||||
* Copyright (c) 2019-2020 GeyserMC. http://geysermc.org
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*
|
||||
* @author GeyserMC
|
||||
* @link https://github.com/GeyserMC/Geyser
|
||||
*/
|
||||
|
||||
package org.geysermc.connector.entity.living.monster;
|
||||
|
||||
import com.github.steveice10.mc.protocol.data.game.entity.metadata.EntityMetadata;
|
||||
import com.nukkitx.math.vector.Vector3f;
|
||||
import com.nukkitx.protocol.bedrock.data.entity.EntityData;
|
||||
import org.geysermc.connector.entity.type.EntityType;
|
||||
import org.geysermc.connector.network.session.GeyserSession;
|
||||
|
||||
public class VexEntity extends MonsterEntity {
|
||||
|
||||
public VexEntity(long entityId, long geyserId, EntityType entityType, Vector3f position, Vector3f motion, Vector3f rotation) {
|
||||
super(entityId, geyserId, entityType, position, motion, rotation);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateBedrockMetadata(EntityMetadata entityMetadata, GeyserSession session) {
|
||||
if (entityMetadata.getId() == 15) {
|
||||
byte xd = (byte) entityMetadata.getValue();
|
||||
// Set the target to the player to force the attack animation
|
||||
// even if the player isn't the target as we dont get the target on Java
|
||||
metadata.put(EntityData.TARGET_EID, (xd & 0x01) == 0x01 ? session.getPlayerEntity().getGeyserId() : 0);
|
||||
}
|
||||
super.updateBedrockMetadata(entityMetadata, session);
|
||||
}
|
||||
}
|
@ -0,0 +1,56 @@
|
||||
/*
|
||||
* Copyright (c) 2019-2020 GeyserMC. http://geysermc.org
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*
|
||||
* @author GeyserMC
|
||||
* @link https://github.com/GeyserMC/Geyser
|
||||
*/
|
||||
|
||||
package org.geysermc.connector.entity.living.monster;
|
||||
|
||||
import com.github.steveice10.mc.protocol.data.game.entity.metadata.EntityMetadata;
|
||||
import com.github.steveice10.mc.protocol.data.game.entity.metadata.VillagerData;
|
||||
import com.nukkitx.math.vector.Vector3f;
|
||||
import com.nukkitx.protocol.bedrock.data.entity.EntityData;
|
||||
import com.nukkitx.protocol.bedrock.data.entity.EntityFlag;
|
||||
import org.geysermc.connector.entity.living.merchant.VillagerEntity;
|
||||
import org.geysermc.connector.entity.type.EntityType;
|
||||
import org.geysermc.connector.network.session.GeyserSession;
|
||||
|
||||
public class ZombieVillagerEntity extends ZombieEntity {
|
||||
|
||||
public ZombieVillagerEntity(long entityId, long geyserId, EntityType entityType, Vector3f position, Vector3f motion, Vector3f rotation) {
|
||||
super(entityId, geyserId, entityType, position, motion, rotation);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateBedrockMetadata(EntityMetadata entityMetadata, GeyserSession session) {
|
||||
if (entityMetadata.getId() == 18) {
|
||||
metadata.getFlags().setFlag(EntityFlag.IS_TRANSFORMING, (boolean) entityMetadata.getValue());
|
||||
metadata.getFlags().setFlag(EntityFlag.SHAKING, (boolean) entityMetadata.getValue());
|
||||
}
|
||||
if (entityMetadata.getId() == 19) {
|
||||
VillagerData villagerData = (VillagerData) entityMetadata.getValue();
|
||||
// Region - only one used on Bedrock
|
||||
metadata.put(EntityData.MARK_VARIANT, VillagerEntity.VILLAGER_REGIONS.get(villagerData.getType()));
|
||||
}
|
||||
super.updateBedrockMetadata(entityMetadata, session);
|
||||
}
|
||||
}
|
@ -47,12 +47,12 @@ public enum EntityType {
|
||||
SHEEP(SheepEntity.class, 13, 1.3f, 0.9f),
|
||||
WOLF(WolfEntity.class, 14, 0.85f, 0.6f),
|
||||
VILLAGER(VillagerEntity.class, 15, 1.8f, 0.6f, 0.6f, 1.62f, "minecraft:villager_v2"),
|
||||
MOOSHROOM(AnimalEntity.class, 16, 1.4f, 0.9f),
|
||||
MOOSHROOM(MooshroomEntity.class, 16, 1.4f, 0.9f),
|
||||
SQUID(SquidEntity.class, 17, 0.8f),
|
||||
RABBIT(RabbitEntity.class, 18, 0.5f, 0.4f),
|
||||
BAT(AmbientEntity.class, 19, 0.9f, 0.5f),
|
||||
BAT(BatEntity.class, 19, 0.9f, 0.5f),
|
||||
IRON_GOLEM(GolemEntity.class, 20, 2.7f, 1.4f),
|
||||
SNOW_GOLEM(GolemEntity.class, 21, 1.9f, 0.7f),
|
||||
SNOW_GOLEM(SnowGolemEntity.class, 21, 1.9f, 0.7f),
|
||||
OCELOT(OcelotEntity.class, 22, 0.35f, 0.3f),
|
||||
HORSE(HorseEntity.class, 23, 1.6f, 1.3965f),
|
||||
DONKEY(ChestedHorseEntity.class, 24, 1.6f, 1.3965f),
|
||||
@ -74,10 +74,10 @@ public enum EntityType {
|
||||
ENDERMAN(EndermanEntity.class, 38, 2.9f, 0.6f),
|
||||
SILVERFISH(MonsterEntity.class, 39, 0.3f, 0.4f),
|
||||
CAVE_SPIDER(MonsterEntity.class, 40, 0.5f, 0.7f),
|
||||
GHAST(FlyingEntity.class, 41, 4.0f),
|
||||
GHAST(GhastEntity.class, 41, 4.0f),
|
||||
MAGMA_CUBE(MagmaCubeEntity.class, 42, 0.51f),
|
||||
BLAZE(BlazeEntity.class, 43, 1.8f, 0.6f),
|
||||
ZOMBIE_VILLAGER(ZombieEntity.class, 44, 1.8f, 0.6f, 0.6f, 1.62f),
|
||||
ZOMBIE_VILLAGER(ZombieVillagerEntity.class, 44, 1.8f, 0.6f, 0.6f, 1.62f, "minecraft:zombie_villager_v2"),
|
||||
WITCH(RaidParticipantEntity.class, 45, 1.8f, 0.6f, 0.6f, 1.62f),
|
||||
STRAY(AbstractSkeletonEntity.class, 46, 1.8f, 0.6f, 0.6f, 1.62f),
|
||||
HUSK(ZombieEntity.class, 47, 1.8f, 0.6f, 0.6f, 1.62f),
|
||||
@ -109,7 +109,7 @@ public enum EntityType {
|
||||
END_CRYSTAL(EnderCrystalEntity.class, 71, 2.0f, 2.0f, 2.0f, 0f, "minecraft:ender_crystal"),
|
||||
FIREWORK_ROCKET(FireworkEntity.class, 72, 0.25f, 0.25f, 0.25f, 0f, "minecraft:fireworks_rocket"),
|
||||
TRIDENT(TridentEntity.class, 73, 0f, 0f, 0f, 0f, "minecraft:thrown_trident"),
|
||||
TURTLE(AnimalEntity.class, 74, 0.4f, 1.2f),
|
||||
TURTLE(TurtleEntity.class, 74, 0.4f, 1.2f),
|
||||
CAT(CatEntity.class, 75, 0.35f, 0.3f),
|
||||
SHULKER_BULLET(Entity.class, 76, 0.3125f),
|
||||
FISHING_BOBBER(FishingHookEntity.class, 77, 0f, 0f, 0f, 0f, "minecraft:fishing_hook"),
|
||||
@ -125,9 +125,9 @@ public enum EntityType {
|
||||
THROWN_POTION(ThrowableEntity.class, 86, 0.25f, 0.25f, 0.25f, 0f, "minecraft:splash_potion"),
|
||||
THROWN_ENDERPEARL(ThrowableEntity.class, 87, 0.25f, 0.25f, 0.25f, 0f, "minecraft:ender_pearl"),
|
||||
LEASH_KNOT(LeashKnotEntity.class, 88, 0.5f, 0.375f),
|
||||
WITHER_SKULL(Entity.class, 89, 0.3125f),
|
||||
WITHER_SKULL(WitherSkullEntity.class, 89, 0.3125f),
|
||||
BOAT(BoatEntity.class, 90, 0.7f, 1.6f, 1.6f, 0.35f),
|
||||
WITHER_SKULL_DANGEROUS(Entity.class, 91, 0f),
|
||||
WITHER_SKULL_DANGEROUS(WitherSkullEntity.class, 91, 0f),
|
||||
LIGHTNING_BOLT(Entity.class, 93, 0f),
|
||||
SMALL_FIREBALL(ItemedFireballEntity.class, 94, 0.3125f),
|
||||
AREA_EFFECT_CLOUD(AreaEffectCloudEntity.class, 95, 0.5f, 1.0f),
|
||||
@ -141,7 +141,7 @@ public enum EntityType {
|
||||
LLAMA_SPIT(Entity.class, 102, 0.25f),
|
||||
EVOKER_FANGS(Entity.class, 103, 0.8f, 0.5f, 0.5f, 0f, "minecraft:evocation_fang"),
|
||||
EVOKER(SpellcasterIllagerEntity.class, 104, 1.95f, 0.6f, 0.6f, 0f, "minecraft:evocation_illager"),
|
||||
VEX(MonsterEntity.class, 105, 0.8f, 0.4f),
|
||||
VEX(VexEntity.class, 105, 0.8f, 0.4f),
|
||||
ICE_BOMB(Entity.class, 106, 0f),
|
||||
BALLOON(Entity.class, 107, 0f), //TODO
|
||||
PUFFERFISH(PufferFishEntity.class, 108, 0.7f, 0.7f),
|
||||
@ -153,7 +153,7 @@ public enum EntityType {
|
||||
FOX(FoxEntity.class, 121, 0.5f, 1.25f),
|
||||
BEE(BeeEntity.class, 122, 0.6f, 0.6f),
|
||||
STRIDER(StriderEntity.class, 125, 1.7f, 0.9f, 0f, 0f, "minecraft:strider"),
|
||||
HOGLIN(AnimalEntity.class, 124, 1.4f, 1.3965f, 1.3965f, 0f, "minecraft:hoglin"),
|
||||
HOGLIN(HoglinEntity.class, 124, 1.4f, 1.3965f, 1.3965f, 0f, "minecraft:hoglin"),
|
||||
ZOGLIN(ZoglinEntity.class, 126, 1.4f, 1.3965f, 1.3965f, 0f, "minecraft:zoglin"),
|
||||
PIGLIN(PiglinEntity.class, 123, 1.95f, 0.6f, 0.6f, 0f, "minecraft:piglin"),
|
||||
PIGLIN_BRUTE(BasePiglinEntity.class, 127, 1.95f, 0.6f, 0.6f, 0f, "minecraft:piglin_brute"),
|
||||
|
@ -26,8 +26,7 @@
|
||||
package org.geysermc.connector.network;
|
||||
|
||||
import com.nukkitx.protocol.bedrock.BedrockPacketCodec;
|
||||
import com.nukkitx.protocol.bedrock.v407.Bedrock_v407;
|
||||
import com.nukkitx.protocol.bedrock.v408.Bedrock_v408;
|
||||
import com.nukkitx.protocol.bedrock.v419.Bedrock_v419;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
@ -40,14 +39,13 @@ public class BedrockProtocol {
|
||||
* Default Bedrock codec that should act as a fallback. Should represent the latest available
|
||||
* release of the game that Geyser supports.
|
||||
*/
|
||||
public static final BedrockPacketCodec DEFAULT_BEDROCK_CODEC = Bedrock_v408.V408_CODEC;
|
||||
public static final BedrockPacketCodec DEFAULT_BEDROCK_CODEC = Bedrock_v419.V419_CODEC;
|
||||
/**
|
||||
* A list of all supported Bedrock versions that can join Geyser
|
||||
*/
|
||||
public static final List<BedrockPacketCodec> SUPPORTED_BEDROCK_CODECS = new ArrayList<>();
|
||||
|
||||
static {
|
||||
SUPPORTED_BEDROCK_CODECS.add(Bedrock_v407.V407_CODEC);
|
||||
SUPPORTED_BEDROCK_CODECS.add(DEFAULT_BEDROCK_CODEC);
|
||||
}
|
||||
|
||||
|
@ -25,7 +25,6 @@
|
||||
|
||||
package org.geysermc.connector.network;
|
||||
|
||||
import com.github.steveice10.mc.protocol.data.message.MessageSerializer;
|
||||
import com.nukkitx.protocol.bedrock.BedrockPong;
|
||||
import com.nukkitx.protocol.bedrock.BedrockServerEventHandler;
|
||||
import com.nukkitx.protocol.bedrock.BedrockServerSession;
|
||||
@ -36,7 +35,7 @@ import org.geysermc.connector.GeyserConnector;
|
||||
import org.geysermc.connector.configuration.GeyserConfiguration;
|
||||
import org.geysermc.connector.network.session.GeyserSession;
|
||||
import org.geysermc.connector.ping.IGeyserPingPassthrough;
|
||||
import org.geysermc.connector.utils.MessageUtils;
|
||||
import org.geysermc.connector.network.translators.chat.MessageTranslator;
|
||||
import org.geysermc.connector.utils.LanguageUtils;
|
||||
|
||||
import java.net.InetSocketAddress;
|
||||
@ -76,7 +75,7 @@ public class ConnectorServerEventHandler implements BedrockServerEventHandler {
|
||||
pong.setIpv4Port(config.getBedrock().getPort());
|
||||
|
||||
if (config.isPassthroughMotd() && pingInfo != null && pingInfo.getDescription() != null) {
|
||||
String[] motd = MessageUtils.getBedrockMessage(MessageSerializer.fromString(pingInfo.getDescription())).split("\n");
|
||||
String[] motd = MessageTranslator.convertMessageLenient(pingInfo.getDescription()).split("\n");
|
||||
String mainMotd = motd[0]; // First line of the motd.
|
||||
String subMotd = (motd.length != 1) ? motd[1] : ""; // Second line of the motd if present, otherwise blank.
|
||||
|
||||
|
@ -25,12 +25,11 @@
|
||||
|
||||
package org.geysermc.connector.network;
|
||||
|
||||
import com.github.steveice10.mc.protocol.data.message.MessageSerializer;
|
||||
import io.netty.buffer.ByteBuf;
|
||||
import io.netty.buffer.ByteBufAllocator;
|
||||
import org.geysermc.connector.common.ping.GeyserPingInfo;
|
||||
import org.geysermc.connector.GeyserConnector;
|
||||
import org.geysermc.connector.utils.MessageUtils;
|
||||
import org.geysermc.connector.network.translators.chat.MessageTranslator;
|
||||
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.IOException;
|
||||
@ -148,7 +147,7 @@ public class QueryPacketHandler {
|
||||
}
|
||||
|
||||
if (connector.getConfig().isPassthroughMotd() && pingInfo != null) {
|
||||
String[] javaMotd = MessageUtils.getBedrockMessage(MessageSerializer.fromString(pingInfo.getDescription())).split("\n");
|
||||
String[] javaMotd = MessageTranslator.convertMessageLenient(pingInfo.getDescription()).split("\n");
|
||||
motd = javaMotd[0].trim(); // First line of the motd.
|
||||
} else {
|
||||
motd = connector.getConfig().getBedrock().getMotd1();
|
||||
|
@ -59,9 +59,11 @@ public class UpstreamPacketHandler extends LoggingPacketHandler {
|
||||
if (packetCodec == null) {
|
||||
if (loginPacket.getProtocolVersion() > BedrockProtocol.DEFAULT_BEDROCK_CODEC.getProtocolVersion()) {
|
||||
// Too early to determine session locale
|
||||
session.getConnector().getLogger().info(LanguageUtils.getLocaleStringLog("geyser.network.outdated.server", BedrockProtocol.DEFAULT_BEDROCK_CODEC.getMinecraftVersion()));
|
||||
session.disconnect(LanguageUtils.getLocaleStringLog("geyser.network.outdated.server", BedrockProtocol.DEFAULT_BEDROCK_CODEC.getMinecraftVersion()));
|
||||
return true;
|
||||
} else if (loginPacket.getProtocolVersion() < BedrockProtocol.DEFAULT_BEDROCK_CODEC.getProtocolVersion()) {
|
||||
session.getConnector().getLogger().info(LanguageUtils.getLocaleStringLog("geyser.network.outdated.client", BedrockProtocol.DEFAULT_BEDROCK_CODEC.getMinecraftVersion()));
|
||||
session.disconnect(LanguageUtils.getLocaleStringLog("geyser.network.outdated.client", BedrockProtocol.DEFAULT_BEDROCK_CODEC.getMinecraftVersion()));
|
||||
return true;
|
||||
}
|
||||
|
@ -34,7 +34,6 @@ import com.github.steveice10.mc.protocol.data.SubProtocol;
|
||||
import com.github.steveice10.mc.protocol.data.game.entity.player.GameMode;
|
||||
import com.github.steveice10.mc.protocol.data.game.statistic.Statistic;
|
||||
import com.github.steveice10.mc.protocol.data.game.window.VillagerTrade;
|
||||
import com.github.steveice10.mc.protocol.data.message.MessageSerializer;
|
||||
import com.github.steveice10.mc.protocol.packet.handshake.client.HandshakePacket;
|
||||
import com.github.steveice10.mc.protocol.packet.ingame.client.world.ClientTeleportConfirmPacket;
|
||||
import com.github.steveice10.mc.protocol.packet.ingame.server.ServerRespawnPacket;
|
||||
@ -65,6 +64,7 @@ import org.geysermc.connector.common.AuthType;
|
||||
import org.geysermc.connector.entity.Entity;
|
||||
import org.geysermc.connector.entity.PlayerEntity;
|
||||
import org.geysermc.connector.inventory.PlayerInventory;
|
||||
import org.geysermc.connector.network.translators.chat.MessageTranslator;
|
||||
import org.geysermc.connector.network.remote.RemoteServer;
|
||||
import org.geysermc.connector.network.session.auth.AuthData;
|
||||
import org.geysermc.connector.network.session.auth.BedrockClientData;
|
||||
@ -74,7 +74,6 @@ import org.geysermc.connector.network.translators.EntityIdentifierRegistry;
|
||||
import org.geysermc.connector.network.translators.PacketTranslatorRegistry;
|
||||
import org.geysermc.connector.network.translators.inventory.EnchantmentInventoryTranslator;
|
||||
import org.geysermc.connector.network.translators.item.ItemRegistry;
|
||||
import org.geysermc.connector.network.translators.world.block.BlockTranslator;
|
||||
import org.geysermc.connector.utils.*;
|
||||
import org.geysermc.floodgate.crypto.FloodgateCipher;
|
||||
import org.geysermc.floodgate.util.BedrockData;
|
||||
@ -142,6 +141,13 @@ public class GeyserSession implements CommandSender {
|
||||
@Setter
|
||||
private boolean jumping;
|
||||
|
||||
/**
|
||||
* The dimension of the player.
|
||||
* As all entities are in the same world, this can be safely applied to all other entities.
|
||||
*/
|
||||
@Setter
|
||||
private String dimension = DimensionUtils.OVERWORLD;
|
||||
|
||||
@Setter
|
||||
private int breakingBlock;
|
||||
|
||||
@ -217,6 +223,12 @@ public class GeyserSession implements CommandSender {
|
||||
@Setter
|
||||
private ScheduledFuture<?> bucketScheduledFuture;
|
||||
|
||||
/**
|
||||
* Sends a movement packet every three seconds if the player hasn't moved. Prevents timeouts when AFK in certain instances.
|
||||
*/
|
||||
@Setter
|
||||
private ScheduledFuture<?> movementSendIfIdle;
|
||||
|
||||
private boolean reducedDebugInfo = false;
|
||||
|
||||
/**
|
||||
@ -471,7 +483,7 @@ public class GeyserSession implements CommandSender {
|
||||
event.getCause().printStackTrace();
|
||||
}
|
||||
|
||||
upstream.disconnect(MessageUtils.getBedrockMessage(MessageSerializer.fromString(event.getReason())));
|
||||
upstream.disconnect(MessageTranslator.convertMessageLenient(event.getReason()));
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -611,12 +623,12 @@ public class GeyserSession implements CommandSender {
|
||||
startGamePacket.setRotation(Vector2f.from(1, 1));
|
||||
|
||||
startGamePacket.setSeed(-1);
|
||||
startGamePacket.setDimensionId(DimensionUtils.javaToBedrock(playerEntity.getDimension()));
|
||||
startGamePacket.setDimensionId(DimensionUtils.javaToBedrock(dimension));
|
||||
startGamePacket.setGeneratorId(1);
|
||||
startGamePacket.setLevelGameType(GameType.SURVIVAL);
|
||||
startGamePacket.setDifficulty(1);
|
||||
startGamePacket.setDefaultSpawn(Vector3i.ZERO);
|
||||
startGamePacket.setAchievementsDisabled(true);
|
||||
startGamePacket.setAchievementsDisabled(!connector.getConfig().isXboxAchievementsEnabled());
|
||||
startGamePacket.setCurrentTick(-1);
|
||||
startGamePacket.setEduEditionOffers(0);
|
||||
startGamePacket.setEduFeaturesEnabled(false);
|
||||
@ -627,7 +639,7 @@ public class GeyserSession implements CommandSender {
|
||||
startGamePacket.getGamerules().add(new GameRuleData<>("showcoordinates", true));
|
||||
startGamePacket.setPlatformBroadcastMode(GamePublishSetting.PUBLIC);
|
||||
startGamePacket.setXblBroadcastMode(GamePublishSetting.PUBLIC);
|
||||
startGamePacket.setCommandsEnabled(true);
|
||||
startGamePacket.setCommandsEnabled(!connector.getConfig().isXboxAchievementsEnabled());
|
||||
startGamePacket.setTexturePacksRequired(false);
|
||||
startGamePacket.setBonusChestEnabled(false);
|
||||
startGamePacket.setStartingWithMap(false);
|
||||
@ -649,7 +661,6 @@ public class GeyserSession implements CommandSender {
|
||||
// startGamePacket.setCurrentTick(0);
|
||||
startGamePacket.setEnchantmentSeed(0);
|
||||
startGamePacket.setMultiplayerCorrelationId("");
|
||||
startGamePacket.setBlockPalette(BlockTranslator.BLOCKS);
|
||||
startGamePacket.setItemEntries(ItemRegistry.ITEMS);
|
||||
startGamePacket.setVanillaVersion("*");
|
||||
startGamePacket.setAuthoritativeMovementMode(AuthoritativeMovementMode.CLIENT);
|
||||
|
@ -33,7 +33,7 @@ import com.nukkitx.protocol.bedrock.packet.BossEventPacket;
|
||||
import com.nukkitx.protocol.bedrock.packet.RemoveEntityPacket;
|
||||
import lombok.AllArgsConstructor;
|
||||
import org.geysermc.connector.network.session.GeyserSession;
|
||||
import org.geysermc.connector.utils.MessageUtils;
|
||||
import org.geysermc.connector.network.translators.chat.MessageTranslator;
|
||||
|
||||
@AllArgsConstructor
|
||||
public class BossBar {
|
||||
@ -58,7 +58,7 @@ public class BossBar {
|
||||
BossEventPacket bossEventPacket = new BossEventPacket();
|
||||
bossEventPacket.setBossUniqueEntityId(entityId);
|
||||
bossEventPacket.setAction(BossEventPacket.Action.CREATE);
|
||||
bossEventPacket.setTitle(MessageUtils.getTranslatedBedrockMessage(title, session.getLocale()));
|
||||
bossEventPacket.setTitle(MessageTranslator.convertMessage(title.toString(), session.getLocale()));
|
||||
bossEventPacket.setHealthPercentage(health);
|
||||
bossEventPacket.setColor(color); //ignored by client
|
||||
bossEventPacket.setOverlay(overlay);
|
||||
@ -72,7 +72,7 @@ public class BossBar {
|
||||
BossEventPacket bossEventPacket = new BossEventPacket();
|
||||
bossEventPacket.setBossUniqueEntityId(entityId);
|
||||
bossEventPacket.setAction(BossEventPacket.Action.UPDATE_NAME);
|
||||
bossEventPacket.setTitle(MessageUtils.getTranslatedBedrockMessage(title, session.getLocale()));
|
||||
bossEventPacket.setTitle(MessageTranslator.convertMessage(title.toString(), session.getLocale()));
|
||||
|
||||
session.sendUpstreamPacket(bossEventPacket);
|
||||
}
|
||||
|
@ -94,12 +94,12 @@ public class ChunkCache {
|
||||
|
||||
public int getBlockAt(int x, int y, int z) {
|
||||
if (!cache) {
|
||||
return BlockTranslator.AIR;
|
||||
return BlockTranslator.JAVA_AIR_ID;
|
||||
}
|
||||
|
||||
Column column = this.getChunk(x >> 4, z >> 4);
|
||||
if (column == null) {
|
||||
return BlockTranslator.AIR;
|
||||
return BlockTranslator.JAVA_AIR_ID;
|
||||
}
|
||||
|
||||
Chunk chunk = column.getChunks()[y >> 4];
|
||||
@ -107,7 +107,7 @@ public class ChunkCache {
|
||||
return chunk.get(x & 0xF, y & 0xF, z & 0xF);
|
||||
}
|
||||
|
||||
return BlockTranslator.AIR;
|
||||
return BlockTranslator.JAVA_AIR_ID;
|
||||
}
|
||||
|
||||
public void removeChunk(int chunkX, int chunkZ) {
|
||||
|
@ -42,7 +42,7 @@ public class BedrockBlockPickRequestTranslator extends PacketTranslator<BlockPic
|
||||
int blockToPick = session.getConnector().getWorldManager().getBlockAt(session, vector.getX(), vector.getY(), vector.getZ());
|
||||
|
||||
// Block is air - chunk caching is probably off
|
||||
if (blockToPick == 0) {
|
||||
if (blockToPick == BlockTranslator.JAVA_AIR_ID) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -25,7 +25,7 @@
|
||||
|
||||
package org.geysermc.connector.network.translators.bedrock;
|
||||
|
||||
import org.geysermc.connector.common.PlatformType;
|
||||
import org.geysermc.common.PlatformType;
|
||||
import org.geysermc.connector.GeyserConnector;
|
||||
import org.geysermc.connector.command.CommandManager;
|
||||
import org.geysermc.connector.network.session.GeyserSession;
|
||||
@ -34,7 +34,7 @@ import org.geysermc.connector.network.translators.Translator;
|
||||
|
||||
import com.github.steveice10.mc.protocol.packet.ingame.client.ClientChatPacket;
|
||||
import com.nukkitx.protocol.bedrock.packet.CommandRequestPacket;
|
||||
import org.geysermc.connector.utils.MessageUtils;
|
||||
import org.geysermc.connector.network.translators.chat.MessageTranslator;
|
||||
|
||||
@Translator(packet = CommandRequestPacket.class)
|
||||
public class BedrockCommandRequestTranslator extends PacketTranslator<CommandRequestPacket> {
|
||||
@ -48,7 +48,7 @@ public class BedrockCommandRequestTranslator extends PacketTranslator<CommandReq
|
||||
} else {
|
||||
String message = packet.getCommand().trim();
|
||||
|
||||
if (MessageUtils.isTooLong(message, session)) {
|
||||
if (MessageTranslator.isTooLong(message, session)) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -117,13 +117,13 @@ public class BedrockInventoryTransactionTranslator extends PacketTranslator<Inve
|
||||
false);
|
||||
session.sendDownstreamPacket(blockPacket);
|
||||
|
||||
// Otherwise boats will not be able to be placed in survival and buckets wont work on mobile
|
||||
if (packet.getItemInHand() != null && packet.getItemInHand().getId() == ItemRegistry.BOAT.getBedrockId()) {
|
||||
// Otherwise boats will not be able to be placed in survival and buckets won't work on mobile
|
||||
if (packet.getItemInHand() != null && ItemRegistry.BOATS.contains(packet.getItemInHand().getId())) {
|
||||
ClientPlayerUseItemPacket itemPacket = new ClientPlayerUseItemPacket(Hand.MAIN_HAND);
|
||||
session.sendDownstreamPacket(itemPacket);
|
||||
}
|
||||
// Check actions, otherwise buckets may be activated when block inventories are accessed
|
||||
else if (packet.getItemInHand() != null && packet.getItemInHand().getId() == ItemRegistry.BUCKET.getBedrockId()) {
|
||||
else if (packet.getItemInHand() != null && ItemRegistry.BUCKETS.contains(packet.getItemInHand().getId())) {
|
||||
// Let the server decide if the bucket item should change, not the client, and revert the changes the client made
|
||||
InventorySlotPacket slotPacket = new InventorySlotPacket();
|
||||
slotPacket.setContainerId(ContainerId.INVENTORY);
|
||||
@ -172,8 +172,8 @@ public class BedrockInventoryTransactionTranslator extends PacketTranslator<Inve
|
||||
}
|
||||
|
||||
// Handled in ITEM_USE if the item is not milk
|
||||
if (packet.getItemInHand() != null && packet.getItemInHand().getId() == ItemRegistry.BUCKET.getBedrockId() &&
|
||||
packet.getItemInHand().getDamage() != 1) {
|
||||
if (packet.getItemInHand() != null && ItemRegistry.BUCKETS.contains(packet.getItemInHand().getId()) &&
|
||||
packet.getItemInHand().getId() != ItemRegistry.MILK_BUCKET.getBedrockId()) {
|
||||
break;
|
||||
}
|
||||
|
||||
@ -194,10 +194,9 @@ public class BedrockInventoryTransactionTranslator extends PacketTranslator<Inve
|
||||
session.sendUpstreamPacket(blockBreakPacket);
|
||||
}
|
||||
|
||||
if (ItemFrameEntity.positionContainsItemFrame(session, packet.getBlockPosition()) &&
|
||||
session.getEntityCache().getEntityByJavaId(ItemFrameEntity.getItemFrameEntityId(session, packet.getBlockPosition())) != null) {
|
||||
ClientPlayerInteractEntityPacket attackPacket = new ClientPlayerInteractEntityPacket((int) ItemFrameEntity.getItemFrameEntityId(session, packet.getBlockPosition()),
|
||||
InteractAction.ATTACK, session.isSneaking());
|
||||
long frameEntityId = ItemFrameEntity.getItemFrameEntityId(session, packet.getBlockPosition());
|
||||
if (frameEntityId != -1 && session.getEntityCache().getEntityByJavaId(frameEntityId) != null) {
|
||||
ClientPlayerInteractEntityPacket attackPacket = new ClientPlayerInteractEntityPacket((int) frameEntityId, InteractAction.ATTACK, session.isSneaking());
|
||||
session.sendDownstreamPacket(attackPacket);
|
||||
break;
|
||||
}
|
||||
|
@ -31,7 +31,7 @@ import org.geysermc.connector.network.translators.Translator;
|
||||
|
||||
import com.github.steveice10.mc.protocol.packet.ingame.client.ClientChatPacket;
|
||||
import com.nukkitx.protocol.bedrock.packet.TextPacket;
|
||||
import org.geysermc.connector.utils.MessageUtils;
|
||||
import org.geysermc.connector.network.translators.chat.MessageTranslator;
|
||||
|
||||
@Translator(packet = TextPacket.class)
|
||||
public class BedrockTextTranslator extends PacketTranslator<TextPacket> {
|
||||
@ -40,7 +40,7 @@ public class BedrockTextTranslator extends PacketTranslator<TextPacket> {
|
||||
public void translate(TextPacket packet, GeyserSession session) {
|
||||
String message = packet.getMessage().replaceAll("^\\.", "/").trim();
|
||||
|
||||
if (MessageUtils.isTooLong(message, session)) {
|
||||
if (MessageTranslator.isTooLong(message, session)) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -25,27 +25,65 @@
|
||||
|
||||
package org.geysermc.connector.network.translators.bedrock.entity.player;
|
||||
|
||||
import com.nukkitx.protocol.bedrock.data.entity.EntityData;
|
||||
import com.nukkitx.protocol.bedrock.data.entity.EntityDataMap;
|
||||
import com.nukkitx.protocol.bedrock.data.entity.EntityFlag;
|
||||
import com.nukkitx.protocol.bedrock.data.inventory.ContainerType;
|
||||
import com.nukkitx.protocol.bedrock.packet.ContainerOpenPacket;
|
||||
import org.geysermc.connector.entity.Entity;
|
||||
import org.geysermc.connector.network.session.GeyserSession;
|
||||
import org.geysermc.connector.network.translators.PacketTranslator;
|
||||
import org.geysermc.connector.network.translators.Translator;
|
||||
|
||||
import com.github.steveice10.mc.protocol.data.game.entity.player.Hand;
|
||||
import com.github.steveice10.mc.protocol.data.game.entity.player.InteractAction;
|
||||
import com.github.steveice10.mc.protocol.data.game.entity.player.PlayerState;
|
||||
import com.github.steveice10.mc.protocol.packet.ingame.client.player.ClientPlayerInteractEntityPacket;
|
||||
import com.github.steveice10.mc.protocol.packet.ingame.client.player.ClientPlayerStatePacket;
|
||||
import com.nukkitx.protocol.bedrock.data.entity.EntityData;
|
||||
import com.nukkitx.protocol.bedrock.data.entity.EntityDataMap;
|
||||
import com.nukkitx.protocol.bedrock.data.entity.EntityFlag;
|
||||
import com.nukkitx.protocol.bedrock.data.inventory.ContainerType;
|
||||
import com.nukkitx.protocol.bedrock.packet.ContainerOpenPacket;
|
||||
import com.nukkitx.protocol.bedrock.packet.InteractPacket;
|
||||
import lombok.Getter;
|
||||
import org.geysermc.connector.entity.Entity;
|
||||
import org.geysermc.connector.entity.type.EntityType;
|
||||
import org.geysermc.connector.network.session.GeyserSession;
|
||||
import org.geysermc.connector.network.translators.PacketTranslator;
|
||||
import org.geysermc.connector.network.translators.Translator;
|
||||
import org.geysermc.connector.network.translators.item.ItemEntry;
|
||||
import org.geysermc.connector.network.translators.item.ItemRegistry;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
@Translator(packet = InteractPacket.class)
|
||||
public class BedrockInteractTranslator extends PacketTranslator<InteractPacket> {
|
||||
|
||||
/**
|
||||
* A list of all foods a horse/donkey can eat on Java Edition.
|
||||
* Used to display interactive tag if needed.
|
||||
*/
|
||||
private static final List<String> DONKEY_AND_HORSE_FOODS = Arrays.asList("golden_apple", "enchanted_golden_apple",
|
||||
"golden_carrot", "sugar", "apple", "wheat", "hay_block");
|
||||
|
||||
/**
|
||||
* A list of all flowers. Used for feeding bees.
|
||||
*/
|
||||
private static final List<String> FLOWERS = Arrays.asList("dandelion", "poppy", "blue_orchid", "allium", "azure_bluet",
|
||||
"red_tulip", "pink_tulip", "white_tulip", "orange_tulip", "cornflower", "lily_of_the_valley", "wither_rose",
|
||||
"sunflower", "lilac", "rose_bush", "peony");
|
||||
|
||||
/**
|
||||
* All entity types that can be leashed on Java Edition
|
||||
*/
|
||||
private static final List<EntityType> LEASHABLE_MOB_TYPES = Arrays.asList(EntityType.BEE, EntityType.CAT, EntityType.CHICKEN,
|
||||
EntityType.COW, EntityType.DOLPHIN, EntityType.DONKEY, EntityType.FOX, EntityType.HOGLIN, EntityType.HORSE, EntityType.SKELETON_HORSE,
|
||||
EntityType.ZOMBIE_HORSE, EntityType.IRON_GOLEM, EntityType.LLAMA, EntityType.TRADER_LLAMA, EntityType.MOOSHROOM,
|
||||
EntityType.MULE, EntityType.OCELOT, EntityType.PARROT, EntityType.PIG, EntityType.POLAR_BEAR, EntityType.RABBIT,
|
||||
EntityType.SHEEP, EntityType.SNOW_GOLEM, EntityType.STRIDER, EntityType.WOLF, EntityType.ZOGLIN);
|
||||
|
||||
private static final List<EntityType> SADDLEABLE_WHEN_TAMED_MOB_TYPES = Arrays.asList(EntityType.DONKEY, EntityType.HORSE,
|
||||
EntityType.ZOMBIE_HORSE, EntityType.MULE);
|
||||
/**
|
||||
* A list of all foods a wolf can eat on Java Edition.
|
||||
* Used to display interactive tag if needed.
|
||||
*/
|
||||
private static final List<String> WOLF_FOODS = Arrays.asList("pufferfish", "tropical_fish", "chicken", "cooked_chicken",
|
||||
"porkchop", "beef", "rabbit", "cooked_porkchop", "cooked_beef", "rotten_flesh", "mutton", "cooked_mutton",
|
||||
"cooked_rabbit");
|
||||
|
||||
@Override
|
||||
public void translate(InteractPacket packet, GeyserSession session) {
|
||||
Entity entity;
|
||||
@ -84,50 +122,232 @@ public class BedrockInteractTranslator extends PacketTranslator<InteractPacket>
|
||||
if (interactEntity == null)
|
||||
return;
|
||||
EntityDataMap entityMetadata = interactEntity.getMetadata();
|
||||
ItemEntry itemEntry = session.getInventory().getItemInHand() == null ? ItemEntry.AIR : ItemRegistry.getItem(session.getInventory().getItemInHand());
|
||||
String javaIdentifierStripped = itemEntry.getJavaIdentifier().replace("minecraft:", "");
|
||||
|
||||
String interactiveTag;
|
||||
// TODO - in the future, update these in the metadata? So the client doesn't have to wiggle their cursor around for it to happen
|
||||
// TODO - also, might be good to abstract out the eating thing. I know there will need to be food tracked for https://github.com/GeyserMC/Geyser/issues/1005 but not all food is breeding food
|
||||
InteractiveTag interactiveTag = InteractiveTag.NONE;
|
||||
if (entityMetadata.getLong(EntityData.LEASH_HOLDER_EID) == session.getPlayerEntity().getGeyserId()) {
|
||||
// Unleash the entity
|
||||
interactiveTag = InteractiveTag.REMOVE_LEASH;
|
||||
} else if (javaIdentifierStripped.equals("saddle") && !entityMetadata.getFlags().getFlag(EntityFlag.SADDLED) &&
|
||||
((SADDLEABLE_WHEN_TAMED_MOB_TYPES.contains(interactEntity.getEntityType()) && entityMetadata.getFlags().getFlag(EntityFlag.TAMED)) ||
|
||||
interactEntity.getEntityType() == EntityType.PIG || interactEntity.getEntityType() == EntityType.STRIDER)) {
|
||||
// Entity can be saddled and the conditions meet (entity can be saddled and, if needed, is tamed)
|
||||
interactiveTag = InteractiveTag.SADDLE;
|
||||
} else if (javaIdentifierStripped.equals("name_tag") && session.getInventory().getItemInHand().getNbt() != null &&
|
||||
session.getInventory().getItemInHand().getNbt().contains("display")) {
|
||||
// Holding a named name tag
|
||||
interactiveTag = InteractiveTag.NAME;
|
||||
} else if (javaIdentifierStripped.equals("lead") && LEASHABLE_MOB_TYPES.contains(interactEntity.getEntityType()) &&
|
||||
entityMetadata.getLong(EntityData.LEASH_HOLDER_EID) == -1L) {
|
||||
// Holding a leash and the mob is leashable for sure
|
||||
// (Plugins can change this behavior so that's something to look into in the far far future)
|
||||
interactiveTag = InteractiveTag.LEASH;
|
||||
} else {
|
||||
switch (interactEntity.getEntityType()) {
|
||||
case BEE:
|
||||
if (FLOWERS.contains(javaIdentifierStripped)) {
|
||||
interactiveTag = InteractiveTag.FEED;
|
||||
}
|
||||
break;
|
||||
case BOAT:
|
||||
interactiveTag = "action.interact.ride.boat";
|
||||
interactiveTag = InteractiveTag.BOARD_BOAT;
|
||||
break;
|
||||
case CAT:
|
||||
if (javaIdentifierStripped.equals("cod") || javaIdentifierStripped.equals("salmon")) {
|
||||
interactiveTag = InteractiveTag.FEED;
|
||||
} else if (entityMetadata.getFlags().getFlag(EntityFlag.TAMED) &&
|
||||
entityMetadata.getLong(EntityData.OWNER_EID) == session.getPlayerEntity().getGeyserId()) {
|
||||
// Tamed and owned by player - can sit/stand
|
||||
interactiveTag = entityMetadata.getFlags().getFlag(EntityFlag.SITTING) ? InteractiveTag.STAND : InteractiveTag.SIT;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case CHICKEN:
|
||||
if (javaIdentifierStripped.contains("seeds")) {
|
||||
interactiveTag = InteractiveTag.FEED;
|
||||
}
|
||||
break;
|
||||
case MOOSHROOM:
|
||||
// Shear the mooshroom
|
||||
if (javaIdentifierStripped.equals("shears")) {
|
||||
interactiveTag = InteractiveTag.MOOSHROOM_SHEAR;
|
||||
break;
|
||||
}
|
||||
// Bowls are acceptable here
|
||||
else if (javaIdentifierStripped.equals("bowl")) {
|
||||
interactiveTag = InteractiveTag.MOOSHROOM_MILK_STEW;
|
||||
break;
|
||||
}
|
||||
// Fall down to COW as this works on mooshrooms
|
||||
case COW:
|
||||
if (javaIdentifierStripped.equals("wheat")) {
|
||||
interactiveTag = InteractiveTag.FEED;
|
||||
} else if (javaIdentifierStripped.equals("bucket")) {
|
||||
// Milk the cow
|
||||
interactiveTag = InteractiveTag.MILK;
|
||||
}
|
||||
break;
|
||||
case CREEPER:
|
||||
if (javaIdentifierStripped.equals("flint_and_steel")) {
|
||||
// Today I learned that you can ignite a creeper with flint and steel! Huh.
|
||||
interactiveTag = InteractiveTag.IGNITE_CREEPER;
|
||||
}
|
||||
break;
|
||||
case DONKEY:
|
||||
case HORSE:
|
||||
case LLAMA:
|
||||
case MULE:
|
||||
if (entityMetadata.getFlags().getFlag(EntityFlag.TAMED) && !entityMetadata.getFlags().getFlag(EntityFlag.CHESTED)
|
||||
&& javaIdentifierStripped.equals("chest")) {
|
||||
// Can attach a chest
|
||||
interactiveTag = InteractiveTag.ATTACH_CHEST;
|
||||
break;
|
||||
}
|
||||
// Intentional fall-through
|
||||
case HORSE:
|
||||
case SKELETON_HORSE:
|
||||
case TRADER_LLAMA:
|
||||
case ZOMBIE_HORSE:
|
||||
// have another switch statement as, while these share mount attributes they don't share food
|
||||
switch (interactEntity.getEntityType()) {
|
||||
case LLAMA:
|
||||
case TRADER_LLAMA:
|
||||
if (javaIdentifierStripped.equals("wheat") || javaIdentifierStripped.equals("hay_block")) {
|
||||
interactiveTag = InteractiveTag.FEED;
|
||||
break;
|
||||
}
|
||||
case DONKEY:
|
||||
case HORSE:
|
||||
// Undead can't eat
|
||||
if (DONKEY_AND_HORSE_FOODS.contains(javaIdentifierStripped)) {
|
||||
interactiveTag = InteractiveTag.FEED;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!entityMetadata.getFlags().getFlag(EntityFlag.BABY)) {
|
||||
// Can't ride a baby
|
||||
if (entityMetadata.getFlags().getFlag(EntityFlag.TAMED)) {
|
||||
interactiveTag = "action.interact.ride.horse";
|
||||
} else {
|
||||
interactiveTag = "action.interact.mount";
|
||||
interactiveTag = InteractiveTag.RIDE_HORSE;
|
||||
} else if (!entityMetadata.getFlags().getFlag(EntityFlag.TAMED) && itemEntry.equals(ItemEntry.AIR)) {
|
||||
// Can't hide an untamed entity without having your hand empty
|
||||
interactiveTag = InteractiveTag.MOUNT;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case FOX:
|
||||
if (javaIdentifierStripped.equals("sweet_berries")) {
|
||||
interactiveTag = InteractiveTag.FEED;
|
||||
}
|
||||
break;
|
||||
case HOGLIN:
|
||||
if (javaIdentifierStripped.equals("crimson_fungus")) {
|
||||
interactiveTag = InteractiveTag.FEED;
|
||||
}
|
||||
break;
|
||||
case MINECART:
|
||||
interactiveTag = "action.interact.ride.minecart";
|
||||
interactiveTag = InteractiveTag.RIDE_MINECART;
|
||||
break;
|
||||
case MINECART_CHEST:
|
||||
case MINECART_COMMAND_BLOCK:
|
||||
case MINECART_HOPPER:
|
||||
interactiveTag = InteractiveTag.OPEN_CONTAINER;
|
||||
break;
|
||||
case OCELOT:
|
||||
if (javaIdentifierStripped.equals("cod") || javaIdentifierStripped.equals("salmon")) {
|
||||
interactiveTag = InteractiveTag.FEED;
|
||||
}
|
||||
break;
|
||||
case PANDA:
|
||||
if (javaIdentifierStripped.equals("bamboo")) {
|
||||
interactiveTag = InteractiveTag.FEED;
|
||||
}
|
||||
break;
|
||||
case PARROT:
|
||||
if (javaIdentifierStripped.contains("seeds") || javaIdentifierStripped.equals("cookie")) {
|
||||
interactiveTag = InteractiveTag.FEED;
|
||||
}
|
||||
break;
|
||||
case PIG:
|
||||
if (entityMetadata.getFlags().getFlag(EntityFlag.SADDLED)) {
|
||||
interactiveTag = "action.interact.mount";
|
||||
} else interactiveTag = "";
|
||||
if (javaIdentifierStripped.equals("carrot") || javaIdentifierStripped.equals("potato") || javaIdentifierStripped.equals("beetroot")) {
|
||||
interactiveTag = InteractiveTag.FEED;
|
||||
} else if (entityMetadata.getFlags().getFlag(EntityFlag.SADDLED)) {
|
||||
interactiveTag = InteractiveTag.MOUNT;
|
||||
}
|
||||
break;
|
||||
case PIGLIN:
|
||||
if (!entityMetadata.getFlags().getFlag(EntityFlag.BABY) && javaIdentifierStripped.equals("gold_ingot")) {
|
||||
interactiveTag = InteractiveTag.BARTER;
|
||||
}
|
||||
break;
|
||||
case RABBIT:
|
||||
if (javaIdentifierStripped.equals("dandelion") || javaIdentifierStripped.equals("carrot") || javaIdentifierStripped.equals("golden_carrot")) {
|
||||
interactiveTag = InteractiveTag.FEED;
|
||||
}
|
||||
break;
|
||||
case SHEEP:
|
||||
if (javaIdentifierStripped.equals("wheat")) {
|
||||
interactiveTag = InteractiveTag.FEED;
|
||||
} else if (!entityMetadata.getFlags().getFlag(EntityFlag.SHEARED)) {
|
||||
if (javaIdentifierStripped.equals("shears")) {
|
||||
// Shear the sheep
|
||||
interactiveTag = InteractiveTag.SHEAR;
|
||||
} else if (javaIdentifierStripped.contains("_dye")) {
|
||||
// Dye the sheep
|
||||
interactiveTag = InteractiveTag.DYE;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case STRIDER:
|
||||
if (javaIdentifierStripped.equals("warped_fungus")) {
|
||||
interactiveTag = InteractiveTag.FEED;
|
||||
} else if (entityMetadata.getFlags().getFlag(EntityFlag.SADDLED)) {
|
||||
interactiveTag = InteractiveTag.RIDE_STRIDER;
|
||||
}
|
||||
break;
|
||||
case TURTLE:
|
||||
if (javaIdentifierStripped.equals("seagrass")) {
|
||||
interactiveTag = InteractiveTag.FEED;
|
||||
}
|
||||
break;
|
||||
case VILLAGER:
|
||||
if (entityMetadata.getInt(EntityData.VARIANT) != 14 && entityMetadata.getInt(EntityData.VARIANT) != 0
|
||||
&& entityMetadata.getFloat(EntityData.SCALE) >= 0.75f) { // Not a nitwit, has a profession and is not a baby
|
||||
interactiveTag = "action.interact.trade";
|
||||
} else interactiveTag = "";
|
||||
interactiveTag = InteractiveTag.TRADE;
|
||||
}
|
||||
break;
|
||||
case WANDERING_TRADER:
|
||||
interactiveTag = "action.interact.trade"; // Since you can always trade with a wandering villager, presumably.
|
||||
interactiveTag = InteractiveTag.TRADE; // Since you can always trade with a wandering villager, presumably.
|
||||
break;
|
||||
case WOLF:
|
||||
if (javaIdentifierStripped.equals("bone") && !entityMetadata.getFlags().getFlag(EntityFlag.TAMED)) {
|
||||
// Bone and untamed - can tame
|
||||
interactiveTag = InteractiveTag.TAME;
|
||||
} else if (WOLF_FOODS.contains(javaIdentifierStripped)) {
|
||||
// Compatible food in hand - feed
|
||||
// Sometimes just sits/stands when the wolf isn't hungry - there doesn't appear to be a way to fix this
|
||||
interactiveTag = InteractiveTag.FEED;
|
||||
} else if (entityMetadata.getFlags().getFlag(EntityFlag.TAMED) &&
|
||||
entityMetadata.getLong(EntityData.OWNER_EID) == session.getPlayerEntity().getGeyserId()) {
|
||||
// Tamed and owned by player - can sit/stand
|
||||
interactiveTag = entityMetadata.getFlags().getFlag(EntityFlag.SITTING) ? InteractiveTag.STAND : InteractiveTag.SIT;
|
||||
}
|
||||
break;
|
||||
case ZOMBIE_VILLAGER:
|
||||
// We can't guarantee the existence of the weakness effect so we just always show it.
|
||||
if (javaIdentifierStripped.equals("golden_apple")) {
|
||||
interactiveTag = InteractiveTag.CURE;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
return; // No need to process any further since there is no interactive tag
|
||||
break;
|
||||
}
|
||||
session.getPlayerEntity().getMetadata().put(EntityData.INTERACTIVE_TAG, interactiveTag);
|
||||
}
|
||||
session.getPlayerEntity().getMetadata().put(EntityData.INTERACTIVE_TAG, interactiveTag.getValue());
|
||||
session.getPlayerEntity().updateBedrockMetadata(session);
|
||||
} else {
|
||||
if (!(session.getPlayerEntity().getMetadata().get(EntityData.INTERACTIVE_TAG) == null) ||
|
||||
!(session.getPlayerEntity().getMetadata().get(EntityData.INTERACTIVE_TAG) == "")) {
|
||||
if (!session.getPlayerEntity().getMetadata().getString(EntityData.INTERACTIVE_TAG).isEmpty()) {
|
||||
// No interactive tag should be sent
|
||||
session.getPlayerEntity().getMetadata().remove(EntityData.INTERACTIVE_TAG);
|
||||
session.getPlayerEntity().updateBedrockMetadata(session);
|
||||
@ -147,4 +367,65 @@ public class BedrockInteractTranslator extends PacketTranslator<InteractPacket>
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* All interactive tags in enum form. For potential API usage.
|
||||
*/
|
||||
public enum InteractiveTag {
|
||||
NONE(true),
|
||||
IGNITE_CREEPER("creeper"),
|
||||
EDIT,
|
||||
LEAVE_BOAT("exit.boat"),
|
||||
FEED,
|
||||
FISH("fishing"),
|
||||
MILK,
|
||||
MOOSHROOM_SHEAR("mooshear"),
|
||||
MOOSHROOM_MILK_STEW("moostew"),
|
||||
BOARD_BOAT("ride.boat"),
|
||||
RIDE_MINECART("ride.minecart"),
|
||||
RIDE_HORSE("ride.horse"),
|
||||
RIDE_STRIDER("ride.strider"),
|
||||
SHEAR,
|
||||
SIT,
|
||||
STAND,
|
||||
TALK,
|
||||
TAME,
|
||||
DYE,
|
||||
CURE,
|
||||
OPEN_CONTAINER("opencontainer"),
|
||||
CREATE_MAP("createMap"),
|
||||
TAKE_PICTURE("takepicture"),
|
||||
SADDLE,
|
||||
MOUNT,
|
||||
BOOST,
|
||||
WRITE,
|
||||
LEASH,
|
||||
REMOVE_LEASH("unleash"),
|
||||
NAME,
|
||||
ATTACH_CHEST("attachchest"),
|
||||
TRADE,
|
||||
POSE_ARMOR_STAND("armorstand.pose"),
|
||||
EQUIP_ARMOR_STAND("armorstand.equip"),
|
||||
READ,
|
||||
WAKE_VILLAGER("wakevillager"),
|
||||
BARTER;
|
||||
|
||||
/**
|
||||
* The full string that should be passed on to the client.
|
||||
*/
|
||||
@Getter
|
||||
private final String value;
|
||||
|
||||
InteractiveTag(boolean isNone) {
|
||||
this.value = "";
|
||||
}
|
||||
|
||||
InteractiveTag(String value) {
|
||||
this.value = "action.interact." + value;
|
||||
}
|
||||
|
||||
InteractiveTag() {
|
||||
this.value = "action.interact." + name().toLowerCase();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -25,7 +25,13 @@
|
||||
|
||||
package org.geysermc.connector.network.translators.bedrock.entity.player;
|
||||
|
||||
import com.github.steveice10.mc.protocol.packet.ingame.client.player.ClientPlayerPositionPacket;
|
||||
import com.github.steveice10.mc.protocol.packet.ingame.client.player.ClientPlayerPositionRotationPacket;
|
||||
import com.nukkitx.math.vector.Vector3d;
|
||||
import com.nukkitx.math.vector.Vector3f;
|
||||
import com.nukkitx.protocol.bedrock.packet.MoveEntityAbsolutePacket;
|
||||
import com.nukkitx.protocol.bedrock.packet.MovePlayerPacket;
|
||||
import com.nukkitx.protocol.bedrock.packet.SetEntityDataPacket;
|
||||
import org.geysermc.connector.common.ChatColor;
|
||||
import org.geysermc.connector.entity.Entity;
|
||||
import org.geysermc.connector.entity.PlayerEntity;
|
||||
@ -34,11 +40,7 @@ import org.geysermc.connector.network.session.GeyserSession;
|
||||
import org.geysermc.connector.network.translators.PacketTranslator;
|
||||
import org.geysermc.connector.network.translators.Translator;
|
||||
|
||||
import com.github.steveice10.mc.protocol.packet.ingame.client.player.ClientPlayerPositionRotationPacket;
|
||||
import com.nukkitx.math.vector.Vector3f;
|
||||
import com.nukkitx.protocol.bedrock.packet.MoveEntityAbsolutePacket;
|
||||
import com.nukkitx.protocol.bedrock.packet.MovePlayerPacket;
|
||||
import com.nukkitx.protocol.bedrock.packet.SetEntityDataPacket;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
@Translator(packet = MovePlayerPacket.class)
|
||||
public class BedrockMovePlayerTranslator extends PacketTranslator<MovePlayerPacket> {
|
||||
@ -59,13 +61,11 @@ public class BedrockMovePlayerTranslator extends PacketTranslator<MovePlayerPack
|
||||
return;
|
||||
}
|
||||
|
||||
// We need to parse the float as a string since casting a float to a double causes us to
|
||||
// lose precision and thus, causes players to get stuck when walking near walls
|
||||
double javaY = packet.getPosition().getY() - EntityType.PLAYER.getOffset();
|
||||
if (packet.isOnGround()) javaY = Math.ceil(javaY * 2) / 2;
|
||||
if (session.getMovementSendIfIdle() != null) {
|
||||
session.getMovementSendIfIdle().cancel(true);
|
||||
}
|
||||
|
||||
Vector3d position = Vector3d.from(Double.parseDouble(Float.toString(packet.getPosition().getX())), javaY,
|
||||
Double.parseDouble(Float.toString(packet.getPosition().getZ())));
|
||||
Vector3d position = adjustBedrockPosition(packet.getPosition(), packet.isOnGround());
|
||||
|
||||
if(!session.confirmTeleport(position)){
|
||||
return;
|
||||
@ -106,6 +106,28 @@ public class BedrockMovePlayerTranslator extends PacketTranslator<MovePlayerPack
|
||||
if (!colliding)
|
||||
*/
|
||||
session.sendDownstreamPacket(playerPositionRotationPacket);
|
||||
|
||||
// Schedule a position send loop if the player is idle
|
||||
session.setMovementSendIfIdle(session.getConnector().getGeneralThreadPool().schedule(() -> sendPositionIfIdle(session),
|
||||
3, TimeUnit.SECONDS));
|
||||
}
|
||||
|
||||
/**
|
||||
* Adjust the Bedrock position before sending to the Java server to account for inaccuracies in movement between
|
||||
* the two versions.
|
||||
*
|
||||
* @param position the current Bedrock position of the client
|
||||
* @param onGround whether the Bedrock player is on the ground
|
||||
* @return the position to send to the Java server.
|
||||
*/
|
||||
private Vector3d adjustBedrockPosition(Vector3f position, boolean onGround) {
|
||||
// We need to parse the float as a string since casting a float to a double causes us to
|
||||
// lose precision and thus, causes players to get stuck when walking near walls
|
||||
double javaY = position.getY() - EntityType.PLAYER.getOffset();
|
||||
if (onGround) javaY = Math.ceil(javaY * 2) / 2;
|
||||
|
||||
return Vector3d.from(Double.parseDouble(Float.toString(position.getX())), javaY,
|
||||
Double.parseDouble(Float.toString(position.getZ())));
|
||||
}
|
||||
|
||||
public boolean isValidMove(GeyserSession session, MovePlayerPacket.Mode mode, Vector3f currentPosition, Vector3f newPosition) {
|
||||
@ -147,4 +169,16 @@ public class BedrockMovePlayerTranslator extends PacketTranslator<MovePlayerPack
|
||||
movePlayerPacket.setMode(MovePlayerPacket.Mode.RESPAWN);
|
||||
session.sendUpstreamPacket(movePlayerPacket);
|
||||
}
|
||||
|
||||
private void sendPositionIfIdle(GeyserSession session) {
|
||||
if (session.isClosed()) return;
|
||||
PlayerEntity entity = session.getPlayerEntity();
|
||||
// Recalculate in case something else changed position
|
||||
Vector3d position = adjustBedrockPosition(entity.getPosition(), entity.isOnGround());
|
||||
ClientPlayerPositionPacket packet = new ClientPlayerPositionPacket(session.getPlayerEntity().isOnGround(),
|
||||
position.getX(), position.getY(), position.getZ());
|
||||
session.sendDownstreamPacket(packet);
|
||||
session.setMovementSendIfIdle(session.getConnector().getGeneralThreadPool().schedule(() -> sendPositionIfIdle(session),
|
||||
3, TimeUnit.SECONDS));
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,278 @@
|
||||
/*
|
||||
* Copyright (c) 2019-2020 GeyserMC. http://geysermc.org
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*
|
||||
* @author GeyserMC
|
||||
* @link https://github.com/GeyserMC/Geyser
|
||||
*/
|
||||
|
||||
package org.geysermc.connector.network.translators.chat;
|
||||
|
||||
import com.github.steveice10.mc.protocol.data.game.scoreboard.TeamColor;
|
||||
import com.github.steveice10.mc.protocol.data.message.style.ChatColor;
|
||||
import com.github.steveice10.mc.protocol.data.message.style.ChatFormat;
|
||||
import net.kyori.adventure.text.Component;
|
||||
import net.kyori.adventure.text.renderer.TranslatableComponentRenderer;
|
||||
import net.kyori.adventure.text.serializer.gson.GsonComponentSerializer;
|
||||
import net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer;
|
||||
import net.kyori.adventure.translation.TranslationRegistry;
|
||||
import org.geysermc.connector.network.session.GeyserSession;
|
||||
import org.geysermc.connector.utils.LanguageUtils;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
public class MessageTranslator {
|
||||
|
||||
// These are used for handling the translations of the messages
|
||||
private static final TranslationRegistry REGISTRY = new MinecraftTranslationRegistry();
|
||||
private static final TranslatableComponentRenderer<Locale> RENDERER = TranslatableComponentRenderer.usingTranslationSource(REGISTRY);
|
||||
|
||||
// Store team colors for player names
|
||||
private static final Map<TeamColor, String> TEAM_COLORS = new HashMap<>();
|
||||
|
||||
static {
|
||||
TEAM_COLORS.put(TeamColor.BLACK, getColor(ChatColor.BLACK));
|
||||
TEAM_COLORS.put(TeamColor.DARK_BLUE, getColor(ChatColor.DARK_BLUE));
|
||||
TEAM_COLORS.put(TeamColor.DARK_GREEN, getColor(ChatColor.DARK_GREEN));
|
||||
TEAM_COLORS.put(TeamColor.DARK_AQUA, getColor(ChatColor.DARK_AQUA));
|
||||
TEAM_COLORS.put(TeamColor.DARK_RED, getColor(ChatColor.DARK_RED));
|
||||
TEAM_COLORS.put(TeamColor.DARK_PURPLE, getColor(ChatColor.DARK_PURPLE));
|
||||
TEAM_COLORS.put(TeamColor.GOLD, getColor(ChatColor.GOLD));
|
||||
TEAM_COLORS.put(TeamColor.GRAY, getColor(ChatColor.GRAY));
|
||||
TEAM_COLORS.put(TeamColor.DARK_GRAY, getColor(ChatColor.DARK_GRAY));
|
||||
TEAM_COLORS.put(TeamColor.BLUE, getColor(ChatColor.BLUE));
|
||||
TEAM_COLORS.put(TeamColor.GREEN, getColor(ChatColor.GREEN));
|
||||
TEAM_COLORS.put(TeamColor.AQUA, getColor(ChatColor.AQUA));
|
||||
TEAM_COLORS.put(TeamColor.RED, getColor(ChatColor.RED));
|
||||
TEAM_COLORS.put(TeamColor.LIGHT_PURPLE, getColor(ChatColor.LIGHT_PURPLE));
|
||||
TEAM_COLORS.put(TeamColor.YELLOW, getColor(ChatColor.YELLOW));
|
||||
TEAM_COLORS.put(TeamColor.WHITE, getColor(ChatColor.WHITE));
|
||||
TEAM_COLORS.put(TeamColor.OBFUSCATED, getFormat(ChatFormat.OBFUSCATED));
|
||||
TEAM_COLORS.put(TeamColor.BOLD, getFormat(ChatFormat.BOLD));
|
||||
TEAM_COLORS.put(TeamColor.STRIKETHROUGH, getFormat(ChatFormat.STRIKETHROUGH));
|
||||
TEAM_COLORS.put(TeamColor.ITALIC, getFormat(ChatFormat.ITALIC));
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert a Java message to the legacy format ready for bedrock
|
||||
*
|
||||
* @param message Java message
|
||||
* @param locale Locale to use for translation strings
|
||||
* @return Parsed and formatted message for bedrock
|
||||
*/
|
||||
public static String convertMessage(String message, String locale) {
|
||||
Component component = GsonComponentSerializer.gson().deserialize(message);
|
||||
|
||||
// Get a Locale from the given locale string
|
||||
Locale localeCode = Locale.forLanguageTag(locale.replace('_', '-'));
|
||||
component = RENDERER.render(component, localeCode);
|
||||
|
||||
return LegacyComponentSerializer.legacySection().serialize(component);
|
||||
}
|
||||
|
||||
public static String convertMessage(String message) {
|
||||
return convertMessage(message, LanguageUtils.getDefaultLocale());
|
||||
}
|
||||
|
||||
/**
|
||||
* Verifies the message is valid JSON in case it's plaintext. Works around GsonComponentSeraializer not using lenient mode.
|
||||
* See https://wiki.vg/Chat for messages sent in lenient mode, and for a description on leniency.
|
||||
*
|
||||
* @param message Potentially lenient JSON message
|
||||
* @param locale Locale to use for translation strings
|
||||
* @return Bedrock formatted message
|
||||
*/
|
||||
public static String convertMessageLenient(String message, String locale) {
|
||||
if (isMessage(message)) {
|
||||
return convertMessage(message, locale);
|
||||
} else {
|
||||
String convertedMessage = convertMessage(convertToJavaMessage(message), locale);
|
||||
|
||||
// We have to do this since Adventure strips the starting reset character
|
||||
if (message.startsWith(getColor(ChatColor.RESET))) {
|
||||
convertedMessage = getColor(ChatColor.RESET) + convertedMessage;
|
||||
}
|
||||
|
||||
return convertedMessage;
|
||||
}
|
||||
}
|
||||
|
||||
public static String convertMessageLenient(String message) {
|
||||
return convertMessageLenient(message, LanguageUtils.getDefaultLocale());
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert a Bedrock message string back to a format Java can understand
|
||||
*
|
||||
* @param message Message to convert
|
||||
* @return The formatted JSON string
|
||||
*/
|
||||
public static String convertToJavaMessage(String message) {
|
||||
Component component = LegacyComponentSerializer.legacySection().deserialize(message);
|
||||
return GsonComponentSerializer.gson().serialize(component);
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if the given text string is a JSON message
|
||||
*
|
||||
* @param text String to test
|
||||
* @return True if its a valid message JSON string, false if not
|
||||
*/
|
||||
public static boolean isMessage(String text) {
|
||||
if (text.trim().isEmpty()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
try {
|
||||
GsonComponentSerializer.gson().deserialize(text);
|
||||
} catch (Exception ex) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert a {@link ChatColor} into a string for inserting into messages
|
||||
*
|
||||
* @param color {@link ChatColor} to convert
|
||||
* @return The converted color string
|
||||
*/
|
||||
private static String getColor(String color) {
|
||||
String base = "\u00a7";
|
||||
switch (color) {
|
||||
case ChatColor.BLACK:
|
||||
base += "0";
|
||||
break;
|
||||
case ChatColor.DARK_BLUE:
|
||||
base += "1";
|
||||
break;
|
||||
case ChatColor.DARK_GREEN:
|
||||
base += "2";
|
||||
break;
|
||||
case ChatColor.DARK_AQUA:
|
||||
base += "3";
|
||||
break;
|
||||
case ChatColor.DARK_RED:
|
||||
base += "4";
|
||||
break;
|
||||
case ChatColor.DARK_PURPLE:
|
||||
base += "5";
|
||||
break;
|
||||
case ChatColor.GOLD:
|
||||
base += "6";
|
||||
break;
|
||||
case ChatColor.GRAY:
|
||||
base += "7";
|
||||
break;
|
||||
case ChatColor.DARK_GRAY:
|
||||
base += "8";
|
||||
break;
|
||||
case ChatColor.BLUE:
|
||||
base += "9";
|
||||
break;
|
||||
case ChatColor.GREEN:
|
||||
base += "a";
|
||||
break;
|
||||
case ChatColor.AQUA:
|
||||
base += "b";
|
||||
break;
|
||||
case ChatColor.RED:
|
||||
base += "c";
|
||||
break;
|
||||
case ChatColor.LIGHT_PURPLE:
|
||||
base += "d";
|
||||
break;
|
||||
case ChatColor.YELLOW:
|
||||
base += "e";
|
||||
break;
|
||||
case ChatColor.WHITE:
|
||||
base += "f";
|
||||
break;
|
||||
case ChatColor.RESET:
|
||||
base += "r";
|
||||
break;
|
||||
default:
|
||||
return "";
|
||||
}
|
||||
|
||||
return base;
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert a {@link ChatFormat} into a string for inserting into messages
|
||||
*
|
||||
* @param format {@link ChatFormat} to convert
|
||||
* @return The converted chat formatting string
|
||||
*/
|
||||
private static String getFormat(ChatFormat format) {
|
||||
StringBuilder str = new StringBuilder();
|
||||
String base = "\u00a7";
|
||||
switch (format) {
|
||||
case OBFUSCATED:
|
||||
base += "k";
|
||||
break;
|
||||
case BOLD:
|
||||
base += "l";
|
||||
break;
|
||||
case STRIKETHROUGH:
|
||||
base += "m";
|
||||
break;
|
||||
case UNDERLINED:
|
||||
base += "n";
|
||||
break;
|
||||
case ITALIC:
|
||||
base += "o";
|
||||
break;
|
||||
default:
|
||||
return "";
|
||||
}
|
||||
|
||||
str.append(base);
|
||||
|
||||
return str.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert a team color to a chat color
|
||||
*
|
||||
* @param teamColor
|
||||
* @return The chat color character
|
||||
*/
|
||||
public static String toChatColor(TeamColor teamColor) {
|
||||
return TEAM_COLORS.getOrDefault(teamColor, "");
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if the given message is over 256 characters (Java edition server chat limit) and sends a message to the user if it is
|
||||
*
|
||||
* @param message Message to check
|
||||
* @param session {@link GeyserSession} for the user
|
||||
* @return True if the message is too long, false if not
|
||||
*/
|
||||
public static boolean isTooLong(String message, GeyserSession session) {
|
||||
if (message.length() > 256) {
|
||||
session.sendMessage(LanguageUtils.getPlayerLocaleString("geyser.chat.too_long", session.getLocale(), message.length()));
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
@ -0,0 +1,81 @@
|
||||
/*
|
||||
* Copyright (c) 2019-2020 GeyserMC. http://geysermc.org
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*
|
||||
* @author GeyserMC
|
||||
* @link https://github.com/GeyserMC/Geyser
|
||||
*/
|
||||
|
||||
package org.geysermc.connector.network.translators.chat;
|
||||
|
||||
import net.kyori.adventure.key.Key;
|
||||
import net.kyori.adventure.translation.TranslationRegistry;
|
||||
import org.checkerframework.checker.nullness.qual.NonNull;
|
||||
import org.checkerframework.checker.nullness.qual.Nullable;
|
||||
import org.geysermc.connector.utils.LocaleUtils;
|
||||
|
||||
import java.text.MessageFormat;
|
||||
import java.util.Locale;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
/**
|
||||
* This class is used for mapping a translation key with the already loaded Java locale data
|
||||
* Used in MessageTranslator.java as part of the KyoriPowered/Adventure library
|
||||
*/
|
||||
public class MinecraftTranslationRegistry implements TranslationRegistry {
|
||||
@Override
|
||||
public @NonNull Key name() {
|
||||
return Key.key("", "");
|
||||
}
|
||||
|
||||
@Override
|
||||
public @Nullable MessageFormat translate(@NonNull String key, @NonNull Locale locale) {
|
||||
// Get the locale string
|
||||
String localeString = LocaleUtils.getLocaleString(key, locale.toString());
|
||||
|
||||
// Replace the `%s` with numbered inserts `{0}`
|
||||
Pattern p = Pattern.compile("%s");
|
||||
Matcher m = p.matcher(localeString);
|
||||
StringBuffer sb = new StringBuffer();
|
||||
int i = 0;
|
||||
while (m.find()) {
|
||||
m.appendReplacement(sb, "{" + (i++) + "}");
|
||||
}
|
||||
m.appendTail(sb);
|
||||
|
||||
return new MessageFormat(sb.toString(), locale);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void defaultLocale(@NonNull Locale locale) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void register(@NonNull String key, @NonNull Locale locale, @NonNull MessageFormat format) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void unregister(@NonNull String key) {
|
||||
|
||||
}
|
||||
}
|
@ -42,6 +42,7 @@ import org.geysermc.connector.common.ChatColor;
|
||||
import org.geysermc.connector.inventory.Inventory;
|
||||
import org.geysermc.connector.network.session.GeyserSession;
|
||||
import org.geysermc.connector.network.translators.inventory.updater.InventoryUpdater;
|
||||
import org.geysermc.connector.network.translators.item.ItemRegistry;
|
||||
import org.geysermc.connector.network.translators.item.ItemTranslator;
|
||||
import org.geysermc.connector.utils.InventoryUtils;
|
||||
import org.geysermc.connector.utils.LocaleUtils;
|
||||
@ -57,9 +58,8 @@ import java.util.List;
|
||||
*/
|
||||
public class EnchantmentInventoryTranslator extends BlockInventoryTranslator {
|
||||
|
||||
private static final int DYE_ID = 351;
|
||||
private static final short LAPIS_DAMAGE = 4;
|
||||
private static final int ENCHANTED_BOOK_ID = 403;
|
||||
private static final int DYE_ID = ItemRegistry.getItemEntry("minecraft:lapis_lazuli").getBedrockId();
|
||||
private static final int ENCHANTED_BOOK_ID = ItemRegistry.getItemEntry("minecraft:enchanted_book").getBedrockId();
|
||||
|
||||
public EnchantmentInventoryTranslator(InventoryUpdater updater) {
|
||||
super(2, "minecraft:hopper[enabled=false,facing=down]", ContainerType.HOPPER, updater);
|
||||
@ -73,8 +73,7 @@ public class EnchantmentInventoryTranslator extends BlockInventoryTranslator {
|
||||
switch (action.getSlot()) {
|
||||
case 1:
|
||||
// Don't allow the slot to be put through if the item isn't lapis
|
||||
if ((action.getToItem().getId() != DYE_ID
|
||||
&& action.getToItem().getDamage() != LAPIS_DAMAGE) && action.getToItem() != ItemData.AIR) {
|
||||
if ((action.getToItem().getId() != DYE_ID) && action.getToItem() != ItemData.AIR) {
|
||||
updateInventory(session, inventory);
|
||||
InventoryUtils.updateCursor(session);
|
||||
return;
|
||||
|
@ -53,9 +53,9 @@ public abstract class InventoryTranslator {
|
||||
put(WindowType.BREWING_STAND, new BrewingInventoryTranslator());
|
||||
put(WindowType.ANVIL, new AnvilInventoryTranslator());
|
||||
put(WindowType.CRAFTING, new CraftingInventoryTranslator());
|
||||
put(WindowType.GRINDSTONE, new GrindstoneInventoryTranslator());
|
||||
//put(WindowType.GRINDSTONE, new GrindstoneInventoryTranslator()); //FIXME
|
||||
put(WindowType.MERCHANT, new MerchantInventoryTranslator());
|
||||
put(WindowType.SMITHING, new SmithingInventoryTranslator());
|
||||
//put(WindowType.SMITHING, new SmithingInventoryTranslator()); //TODO for server authoritative inventories
|
||||
|
||||
InventoryTranslator furnace = new FurnaceInventoryTranslator();
|
||||
put(WindowType.FURNACE, furnace);
|
||||
|
@ -34,9 +34,10 @@ import lombok.ToString;
|
||||
@ToString
|
||||
public class ItemEntry {
|
||||
|
||||
public static ItemEntry AIR = new ItemEntry("minecraft:air", 0, 0, 0, false);
|
||||
public static ItemEntry AIR = new ItemEntry("minecraft:air", "minecraft:air", 0, 0, 0, false);
|
||||
|
||||
private final String javaIdentifier;
|
||||
private final String bedrockIdentifier;
|
||||
private final int javaId;
|
||||
private final int bedrockId;
|
||||
private final int bedrockData;
|
||||
|
@ -34,6 +34,8 @@ import com.nukkitx.protocol.bedrock.data.inventory.ItemData;
|
||||
import com.nukkitx.protocol.bedrock.packet.StartGamePacket;
|
||||
import it.unimi.dsi.fastutil.ints.Int2ObjectMap;
|
||||
import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap;
|
||||
import it.unimi.dsi.fastutil.ints.IntArrayList;
|
||||
import it.unimi.dsi.fastutil.ints.IntList;
|
||||
import org.geysermc.connector.GeyserConnector;
|
||||
import org.geysermc.connector.utils.FileUtils;
|
||||
import org.geysermc.connector.utils.LanguageUtils;
|
||||
@ -56,13 +58,21 @@ public class ItemRegistry {
|
||||
public static final Int2ObjectMap<ItemEntry> ITEM_ENTRIES = new Int2ObjectOpenHashMap<>();
|
||||
|
||||
/**
|
||||
* Boat item entry, used in BedrockInventoryTransactionTranslator.java
|
||||
* Bamboo item entry, used in PandaEntity.java
|
||||
*/
|
||||
public static ItemEntry BOAT;
|
||||
public static ItemEntry BAMBOO;
|
||||
/**
|
||||
* Bucket item entry, used in BedrockInventoryTransactionTranslator.java
|
||||
* Boat item entries, used in BedrockInventoryTransactionTranslator.java
|
||||
*/
|
||||
public static ItemEntry BUCKET;
|
||||
public static IntList BOATS = new IntArrayList();
|
||||
/**
|
||||
* Bucket item entries (excluding the milk bucket), used in BedrockInventoryTransactionTranslator.java
|
||||
*/
|
||||
public static IntList BUCKETS = new IntArrayList();
|
||||
/**
|
||||
* Empty item bucket, used in BedrockInventoryTransactionTranslator.java
|
||||
*/
|
||||
public static ItemEntry MILK_BUCKET;
|
||||
/**
|
||||
* Egg item entry, used in JavaEntityStatusTranslator.java
|
||||
*/
|
||||
@ -75,6 +85,10 @@ public class ItemRegistry {
|
||||
* Shield item entry, used in Entity.java and LivingEntity.java
|
||||
*/
|
||||
public static ItemEntry SHIELD;
|
||||
/**
|
||||
* Wheat item entry, used in AbstractHorseEntity.java
|
||||
*/
|
||||
public static ItemEntry WHEAT;
|
||||
|
||||
public static int BARRIER_INDEX = 0;
|
||||
|
||||
@ -84,11 +98,14 @@ public class ItemRegistry {
|
||||
|
||||
static {
|
||||
/* Load item palette */
|
||||
InputStream stream = FileUtils.getResource("bedrock/items.json");
|
||||
InputStream stream = FileUtils.getResource("bedrock/runtime_item_states.json");
|
||||
|
||||
TypeReference<List<JsonNode>> itemEntriesType = new TypeReference<List<JsonNode>>() {
|
||||
};
|
||||
|
||||
// Used to get the Bedrock namespaced ID (in instances where there are small differences)
|
||||
Int2ObjectMap<String> bedrockIdToIdentifier = new Int2ObjectOpenHashMap<>();
|
||||
|
||||
List<JsonNode> itemEntries;
|
||||
try {
|
||||
itemEntries = GeyserConnector.JSON_MAPPER.readValue(stream, itemEntriesType);
|
||||
@ -96,8 +113,14 @@ public class ItemRegistry {
|
||||
throw new AssertionError(LanguageUtils.getLocaleStringLog("geyser.toolbox.fail.runtime_bedrock"), e);
|
||||
}
|
||||
|
||||
int lodestoneCompassId = 0;
|
||||
|
||||
for (JsonNode entry : itemEntries) {
|
||||
ITEMS.add(new StartGamePacket.ItemEntry(entry.get("name").textValue(), (short) entry.get("id").intValue()));
|
||||
bedrockIdToIdentifier.put(entry.get("id").intValue(), entry.get("name").textValue());
|
||||
if (entry.get("name").textValue().equals("minecraft:lodestone_compass")) {
|
||||
lodestoneCompassId = entry.get("id").intValue();
|
||||
}
|
||||
}
|
||||
|
||||
stream = FileUtils.getResource("mappings/items.json");
|
||||
@ -113,28 +136,29 @@ public class ItemRegistry {
|
||||
Iterator<Map.Entry<String, JsonNode>> iterator = items.fields();
|
||||
while (iterator.hasNext()) {
|
||||
Map.Entry<String, JsonNode> entry = iterator.next();
|
||||
int bedrockId = entry.getValue().get("bedrock_id").intValue();
|
||||
String bedrockIdentifier = bedrockIdToIdentifier.get(bedrockId);
|
||||
if (bedrockIdentifier == null) {
|
||||
throw new RuntimeException("Missing Bedrock ID in mappings!: " + bedrockId);
|
||||
}
|
||||
if (entry.getValue().has("tool_type")) {
|
||||
if (entry.getValue().has("tool_tier")) {
|
||||
ITEM_ENTRIES.put(itemIndex, new ToolItemEntry(
|
||||
entry.getKey(), itemIndex,
|
||||
entry.getValue().get("bedrock_id").intValue(),
|
||||
entry.getKey(), bedrockIdentifier, itemIndex, bedrockId,
|
||||
entry.getValue().get("bedrock_data").intValue(),
|
||||
entry.getValue().get("tool_type").textValue(),
|
||||
entry.getValue().get("tool_tier").textValue(),
|
||||
entry.getValue().get("is_block") != null && entry.getValue().get("is_block").booleanValue()));
|
||||
} else {
|
||||
ITEM_ENTRIES.put(itemIndex, new ToolItemEntry(
|
||||
entry.getKey(), itemIndex,
|
||||
entry.getValue().get("bedrock_id").intValue(),
|
||||
entry.getKey(), bedrockIdentifier, itemIndex, bedrockId,
|
||||
entry.getValue().get("bedrock_data").intValue(),
|
||||
entry.getValue().get("tool_type").textValue(),
|
||||
"",
|
||||
entry.getValue().get("is_block").booleanValue()));
|
||||
"", entry.getValue().get("is_block").booleanValue()));
|
||||
}
|
||||
} else {
|
||||
ITEM_ENTRIES.put(itemIndex, new ItemEntry(
|
||||
entry.getKey(), itemIndex,
|
||||
entry.getValue().get("bedrock_id").intValue(),
|
||||
entry.getKey(), bedrockIdentifier, itemIndex, bedrockId,
|
||||
entry.getValue().get("bedrock_data").intValue(),
|
||||
entry.getValue().get("is_block") != null && entry.getValue().get("is_block").booleanValue()));
|
||||
}
|
||||
@ -142,8 +166,8 @@ public class ItemRegistry {
|
||||
case "minecraft:barrier":
|
||||
BARRIER_INDEX = itemIndex;
|
||||
break;
|
||||
case "minecraft:oak_boat":
|
||||
BOAT = ITEM_ENTRIES.get(itemIndex);
|
||||
case "minecraft:bamboo":
|
||||
BAMBOO = ITEM_ENTRIES.get(itemIndex);
|
||||
break;
|
||||
case "minecraft:egg":
|
||||
EGG = ITEM_ENTRIES.get(itemIndex);
|
||||
@ -154,18 +178,32 @@ public class ItemRegistry {
|
||||
case "minecraft:shield":
|
||||
SHIELD = ITEM_ENTRIES.get(itemIndex);
|
||||
break;
|
||||
case "minecraft:bucket":
|
||||
BUCKET = ITEM_ENTRIES.get(itemIndex);
|
||||
case "minecraft:milk_bucket":
|
||||
MILK_BUCKET = ITEM_ENTRIES.get(itemIndex);
|
||||
break;
|
||||
case "minecraft:wheat":
|
||||
WHEAT = ITEM_ENTRIES.get(itemIndex);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
if (entry.getKey().contains("boat")) {
|
||||
BOATS.add(entry.getValue().get("bedrock_id").intValue());
|
||||
} else if (entry.getKey().contains("bucket") && !entry.getKey().contains("milk")) {
|
||||
BUCKETS.add(entry.getValue().get("bedrock_id").intValue());
|
||||
}
|
||||
|
||||
itemIndex++;
|
||||
}
|
||||
|
||||
// Add the loadstonecompass since it doesn't exist on java but we need it for item conversion
|
||||
ITEM_ENTRIES.put(itemIndex, new ItemEntry("minecraft:lodestonecompass", itemIndex, 741, 0, false));
|
||||
if (lodestoneCompassId == 0) {
|
||||
throw new RuntimeException("Lodestone compass not found in item palette!");
|
||||
}
|
||||
|
||||
// Add the loadstone compass since it doesn't exist on java but we need it for item conversion
|
||||
ITEM_ENTRIES.put(itemIndex, new ItemEntry("minecraft:lodestone_compass", "minecraft:lodestone_compass", itemIndex,
|
||||
lodestoneCompassId, 0, false));
|
||||
|
||||
/* Load creative items */
|
||||
stream = FileUtils.getResource("bedrock/creative_items.json");
|
||||
@ -226,25 +264,14 @@ public class ItemRegistry {
|
||||
* @return an item entry from the given java edition identifier
|
||||
*/
|
||||
public static ItemEntry getItemEntry(String javaIdentifier) {
|
||||
return JAVA_IDENTIFIER_MAP.computeIfAbsent(javaIdentifier, key -> ITEM_ENTRIES.values()
|
||||
.stream().filter(itemEntry -> itemEntry.getJavaIdentifier().equals(key)).findFirst().orElse(null));
|
||||
}
|
||||
|
||||
/**
|
||||
* Finds the Bedrock string identifier of an ItemEntry
|
||||
*
|
||||
* @param entry the ItemEntry to search for
|
||||
* @return the Bedrock identifier
|
||||
*/
|
||||
public static String getBedrockIdentifer(ItemEntry entry) {
|
||||
String blockName = "";
|
||||
for (StartGamePacket.ItemEntry startGamePacketItemEntry : ItemRegistry.ITEMS) {
|
||||
if (startGamePacketItemEntry.getId() == (short) entry.getBedrockId()) {
|
||||
blockName = startGamePacketItemEntry.getIdentifier(); // Find the Bedrock string name
|
||||
break;
|
||||
return JAVA_IDENTIFIER_MAP.computeIfAbsent(javaIdentifier, key -> {
|
||||
for (ItemEntry entry : ITEM_ENTRIES.values()) {
|
||||
if (entry.getJavaIdentifier().equals(key)) {
|
||||
return entry;
|
||||
}
|
||||
}
|
||||
return blockName;
|
||||
return null;
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -26,7 +26,6 @@
|
||||
package org.geysermc.connector.network.translators.item;
|
||||
|
||||
import com.github.steveice10.mc.protocol.data.game.entity.metadata.ItemStack;
|
||||
import com.github.steveice10.mc.protocol.data.message.MessageSerializer;
|
||||
import com.github.steveice10.opennbt.tag.builtin.*;
|
||||
import com.nukkitx.nbt.NbtList;
|
||||
import com.nukkitx.nbt.NbtMap;
|
||||
@ -35,23 +34,19 @@ import com.nukkitx.nbt.NbtType;
|
||||
import com.nukkitx.protocol.bedrock.data.inventory.ItemData;
|
||||
import it.unimi.dsi.fastutil.ints.Int2ObjectMap;
|
||||
import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap;
|
||||
import net.kyori.adventure.text.Component;
|
||||
import net.kyori.adventure.text.serializer.gson.GsonComponentSerializer;
|
||||
import net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer;
|
||||
import org.geysermc.connector.GeyserConnector;
|
||||
import org.geysermc.connector.network.session.GeyserSession;
|
||||
import org.geysermc.connector.network.translators.ItemRemapper;
|
||||
import org.geysermc.connector.network.translators.chat.MessageTranslator;
|
||||
import org.geysermc.connector.network.translators.world.block.BlockTranslator;
|
||||
import org.geysermc.connector.utils.FileUtils;
|
||||
import org.geysermc.connector.utils.LanguageUtils;
|
||||
import org.geysermc.connector.utils.MessageUtils;
|
||||
import org.reflections.Reflections;
|
||||
|
||||
import java.util.*;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
public abstract class ItemTranslator {
|
||||
|
||||
private static final Int2ObjectMap<ItemTranslator> ITEM_STACK_TRANSLATORS = new Int2ObjectOpenHashMap<>();
|
||||
private static final List<NbtItemStackTranslator> NBT_TRANSLATORS;
|
||||
|
||||
@ -220,7 +215,7 @@ public abstract class ItemTranslator {
|
||||
public abstract List<ItemEntry> getAppliedItems();
|
||||
|
||||
public NbtMap translateNbtToBedrock(com.github.steveice10.opennbt.tag.builtin.CompoundTag tag) {
|
||||
Map<String, Object> javaValue = new HashMap<>();
|
||||
NbtMapBuilder builder = NbtMap.builder();
|
||||
if (tag.getValue() != null && !tag.getValue().isEmpty()) {
|
||||
for (String str : tag.getValue().keySet()) {
|
||||
com.github.steveice10.opennbt.tag.builtin.Tag javaTag = tag.get(str);
|
||||
@ -228,11 +223,9 @@ public abstract class ItemTranslator {
|
||||
if (translatedTag == null)
|
||||
continue;
|
||||
|
||||
javaValue.put(javaTag.getName(), translatedTag);
|
||||
builder.put(javaTag.getName(), translatedTag);
|
||||
}
|
||||
}
|
||||
NbtMapBuilder builder = NbtMap.builder();
|
||||
javaValue.forEach(builder::put);
|
||||
return builder.build();
|
||||
}
|
||||
|
||||
@ -388,19 +381,11 @@ public abstract class ItemTranslator {
|
||||
public static void translateDisplayProperties(GeyserSession session, CompoundTag tag) {
|
||||
if (tag != null) {
|
||||
CompoundTag display = tag.get("display");
|
||||
if (display != null && !display.isEmpty() && display.contains("Name")) {
|
||||
if (display != null && display.contains("Name")) {
|
||||
String name = ((StringTag) display.get("Name")).getValue();
|
||||
|
||||
// If its not a message convert it
|
||||
if (!MessageUtils.isMessage(name)) {
|
||||
Component component = LegacyComponentSerializer.legacySection().deserialize(name);
|
||||
name = GsonComponentSerializer.gson().serialize(component);
|
||||
}
|
||||
|
||||
// Check if its a message to translate
|
||||
if (MessageUtils.isMessage(name)) {
|
||||
// Get the translated name
|
||||
name = MessageUtils.getTranslatedBedrockMessage(MessageSerializer.fromString(name), session.getLocale());
|
||||
// Get the translated name and prefix it with a reset char
|
||||
name = MessageTranslator.convertMessageLenient(name, session.getLocale());
|
||||
|
||||
// Add the new name tag
|
||||
display.put(new StringTag("Name", name));
|
||||
@ -410,7 +395,6 @@ public abstract class ItemTranslator {
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if an {@link ItemStack} is equal to another item stack
|
||||
|
@ -32,8 +32,8 @@ public class ToolItemEntry extends ItemEntry {
|
||||
private final String toolType;
|
||||
private final String toolTier;
|
||||
|
||||
public ToolItemEntry(String javaIdentifier, int javaId, int bedrockId, int bedrockData, String toolType, String toolTier, boolean isBlock) {
|
||||
super(javaIdentifier, javaId, bedrockId, bedrockData, isBlock);
|
||||
public ToolItemEntry(String javaIdentifier, String bedrockIdentifier, int javaId, int bedrockId, int bedrockData, String toolType, String toolTier, boolean isBlock) {
|
||||
super(javaIdentifier, bedrockIdentifier, javaId, bedrockId, bedrockData, isBlock);
|
||||
this.toolType = toolType;
|
||||
this.toolTier = toolTier;
|
||||
}
|
||||
|
@ -26,20 +26,16 @@
|
||||
package org.geysermc.connector.network.translators.item.translators;
|
||||
|
||||
import com.github.steveice10.mc.protocol.data.game.entity.metadata.ItemStack;
|
||||
import com.github.steveice10.opennbt.tag.builtin.CompoundTag;
|
||||
import com.github.steveice10.opennbt.tag.builtin.IntTag;
|
||||
import com.github.steveice10.opennbt.tag.builtin.ListTag;
|
||||
import com.github.steveice10.opennbt.tag.builtin.StringTag;
|
||||
import com.github.steveice10.opennbt.tag.builtin.Tag;
|
||||
import com.github.steveice10.opennbt.tag.builtin.*;
|
||||
import com.nukkitx.nbt.NbtList;
|
||||
import com.nukkitx.nbt.NbtMap;
|
||||
import com.nukkitx.nbt.NbtMapBuilder;
|
||||
import com.nukkitx.nbt.NbtType;
|
||||
import com.nukkitx.protocol.bedrock.data.inventory.ItemData;
|
||||
import org.geysermc.connector.network.translators.ItemRemapper;
|
||||
import org.geysermc.connector.network.translators.item.ItemEntry;
|
||||
import org.geysermc.connector.network.translators.item.ItemRegistry;
|
||||
import org.geysermc.connector.network.translators.item.ItemTranslator;
|
||||
import org.geysermc.connector.network.translators.item.ItemEntry;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
@ -49,54 +45,13 @@ import java.util.stream.Collectors;
|
||||
|
||||
@ItemRemapper
|
||||
public class BannerTranslator extends ItemTranslator {
|
||||
|
||||
private final List<ItemEntry> appliedItems;
|
||||
|
||||
public BannerTranslator() {
|
||||
appliedItems = ItemRegistry.ITEM_ENTRIES.values().stream().filter(entry -> entry.getJavaIdentifier().endsWith("banner")).collect(Collectors.toList());
|
||||
}
|
||||
|
||||
@Override
|
||||
public ItemData translateToBedrock(ItemStack itemStack, ItemEntry itemEntry) {
|
||||
if (itemStack.getNbt() == null) return super.translateToBedrock(itemStack, itemEntry);
|
||||
|
||||
ItemData itemData = super.translateToBedrock(itemStack, itemEntry);
|
||||
|
||||
CompoundTag blockEntityTag = itemStack.getNbt().get("BlockEntityTag");
|
||||
if (blockEntityTag.contains("Patterns")) {
|
||||
ListTag patterns = blockEntityTag.get("Patterns");
|
||||
|
||||
NbtMapBuilder builder = itemData.getTag().toBuilder();
|
||||
builder.put("Patterns", convertBannerPattern(patterns));
|
||||
|
||||
itemData = ItemData.of(itemData.getId(), itemData.getDamage(), itemData.getCount(), builder.build());
|
||||
}
|
||||
|
||||
return itemData;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ItemStack translateToJava(ItemData itemData, ItemEntry itemEntry) {
|
||||
if (itemData.getTag() == null) return super.translateToJava(itemData, itemEntry);
|
||||
|
||||
ItemStack itemStack = super.translateToJava(itemData, itemEntry);
|
||||
|
||||
NbtMap nbtTag = itemData.getTag();
|
||||
if (nbtTag.containsKey("Patterns", NbtType.COMPOUND)) {
|
||||
List<NbtMap> patterns = nbtTag.getList("Patterns", NbtType.COMPOUND);
|
||||
|
||||
CompoundTag blockEntityTag = new CompoundTag("BlockEntityTag");
|
||||
blockEntityTag.put(convertBannerPattern(patterns));
|
||||
|
||||
itemStack.getNbt().put(blockEntityTag);
|
||||
}
|
||||
|
||||
return itemStack;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<ItemEntry> getAppliedItems() {
|
||||
return appliedItems;
|
||||
appliedItems = ItemRegistry.ITEM_ENTRIES.values()
|
||||
.stream()
|
||||
.filter(entry -> entry.getJavaIdentifier().endsWith("banner"))
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
|
||||
/**
|
||||
@ -133,7 +88,6 @@ public class BannerTranslator extends ItemTranslator {
|
||||
|
||||
return NbtMap.builder()
|
||||
.putInt("Color", 15 - (int) pattern.get("Color").getValue())
|
||||
.putString("Pattern", (String) pattern.get("Pattern").getValue())
|
||||
.putString("Pattern", patternName)
|
||||
.build();
|
||||
}
|
||||
@ -147,8 +101,7 @@ public class BannerTranslator extends ItemTranslator {
|
||||
public static ListTag convertBannerPattern(List<NbtMap> patterns) {
|
||||
List<Tag> tagsList = new ArrayList<>();
|
||||
for (Object patternTag : patterns) {
|
||||
CompoundTag newPatternTag = getJavaBannerPattern((NbtMap) patternTag);
|
||||
tagsList.add(newPatternTag);
|
||||
tagsList.add(getJavaBannerPattern((NbtMap) patternTag));
|
||||
}
|
||||
|
||||
return new ListTag("Patterns", tagsList);
|
||||
@ -167,4 +120,51 @@ public class BannerTranslator extends ItemTranslator {
|
||||
|
||||
return new CompoundTag("", tags);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ItemData translateToBedrock(ItemStack itemStack, ItemEntry itemEntry) {
|
||||
if (itemStack.getNbt() == null) {
|
||||
return super.translateToBedrock(itemStack, itemEntry);
|
||||
}
|
||||
|
||||
ItemData itemData = super.translateToBedrock(itemStack, itemEntry);
|
||||
|
||||
CompoundTag blockEntityTag = itemStack.getNbt().get("BlockEntityTag");
|
||||
if (blockEntityTag != null && blockEntityTag.contains("Patterns")) {
|
||||
ListTag patterns = blockEntityTag.get("Patterns");
|
||||
|
||||
NbtMapBuilder builder = itemData.getTag().toBuilder();
|
||||
builder.put("Patterns", convertBannerPattern(patterns));
|
||||
|
||||
itemData = ItemData.of(itemData.getId(), itemData.getDamage(), itemData.getCount(), builder.build());
|
||||
}
|
||||
|
||||
return itemData;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ItemStack translateToJava(ItemData itemData, ItemEntry itemEntry) {
|
||||
if (itemData.getTag() == null) {
|
||||
return super.translateToJava(itemData, itemEntry);
|
||||
}
|
||||
|
||||
ItemStack itemStack = super.translateToJava(itemData, itemEntry);
|
||||
|
||||
NbtMap nbtTag = itemData.getTag();
|
||||
if (nbtTag.containsKey("Patterns", NbtType.COMPOUND)) {
|
||||
List<NbtMap> patterns = nbtTag.getList("Patterns", NbtType.COMPOUND);
|
||||
|
||||
CompoundTag blockEntityTag = new CompoundTag("BlockEntityTag");
|
||||
blockEntityTag.put(convertBannerPattern(patterns));
|
||||
|
||||
itemStack.getNbt().put(blockEntityTag);
|
||||
}
|
||||
|
||||
return itemStack;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<ItemEntry> getAppliedItems() {
|
||||
return appliedItems;
|
||||
}
|
||||
}
|
||||
|
@ -53,7 +53,7 @@ public class CompassTranslator extends ItemTranslator {
|
||||
Tag lodestoneTag = itemStack.getNbt().get("LodestoneTracked");
|
||||
if (lodestoneTag instanceof ByteTag) {
|
||||
// Get the fake lodestonecompass entry
|
||||
itemEntry = ItemRegistry.getItemEntry("minecraft:lodestonecompass");
|
||||
itemEntry = ItemRegistry.getItemEntry("minecraft:lodestone_compass");
|
||||
|
||||
// Get the loadstone pos
|
||||
CompoundTag loadstonePos = itemStack.getNbt().get("LodestonePos");
|
||||
@ -83,7 +83,7 @@ public class CompassTranslator extends ItemTranslator {
|
||||
@Override
|
||||
public ItemStack translateToJava(ItemData itemData, ItemEntry itemEntry) {
|
||||
boolean isLoadstone = false;
|
||||
if (itemEntry.getJavaIdentifier().equals("minecraft:lodestonecompass")) {
|
||||
if (itemEntry.getBedrockIdentifier().equals("minecraft:lodestone_compass")) {
|
||||
// Revert the entry back to the compass
|
||||
itemEntry = ItemRegistry.getItemEntry("minecraft:compass");
|
||||
|
||||
|
@ -37,7 +37,6 @@ import org.geysermc.connector.network.session.GeyserSession;
|
||||
import org.geysermc.connector.network.translators.ItemRemapper;
|
||||
import org.geysermc.connector.network.translators.item.ItemEntry;
|
||||
import org.geysermc.connector.network.translators.item.NbtItemStackTranslator;
|
||||
import org.geysermc.connector.utils.MessageUtils;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
@ -108,7 +107,7 @@ public class BasicItemTranslator extends NbtItemStackTranslator {
|
||||
private String toBedrockMessage(StringTag tag) {
|
||||
String message = tag.getValue();
|
||||
if (message == null) return null;
|
||||
TextComponent component = (TextComponent) MessageUtils.phraseJavaMessage(message);
|
||||
TextComponent component = (TextComponent) GsonComponentSerializer.gson().deserialize(message);
|
||||
String legacy = LegacyComponentSerializer.legacySection().serialize(component);
|
||||
if (hasFormatting(LegacyComponentSerializer.legacySection().deserialize(legacy))) {
|
||||
return "§r" + legacy;
|
||||
|
@ -33,7 +33,7 @@ import org.geysermc.connector.network.session.GeyserSession;
|
||||
import org.geysermc.connector.network.translators.ItemRemapper;
|
||||
import org.geysermc.connector.network.translators.item.NbtItemStackTranslator;
|
||||
import org.geysermc.connector.network.translators.item.ItemEntry;
|
||||
import org.geysermc.connector.utils.MessageUtils;
|
||||
import org.geysermc.connector.network.translators.chat.MessageTranslator;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
@ -56,7 +56,7 @@ public class BookPagesTranslator extends NbtItemStackTranslator {
|
||||
|
||||
CompoundTag pageTag = new CompoundTag("");
|
||||
pageTag.put(new StringTag("photoname", ""));
|
||||
pageTag.put(new StringTag("text", MessageUtils.getBedrockMessageLenient(textTag.getValue())));
|
||||
pageTag.put(new StringTag("text", MessageTranslator.convertMessageLenient(textTag.getValue())));
|
||||
pages.add(pageTag);
|
||||
}
|
||||
|
||||
@ -78,7 +78,7 @@ public class BookPagesTranslator extends NbtItemStackTranslator {
|
||||
CompoundTag pageTag = (CompoundTag) tag;
|
||||
|
||||
StringTag textTag = pageTag.get("text");
|
||||
pages.add(new StringTag(MessageUtils.getJavaMessage(textTag.getValue())));
|
||||
pages.add(new StringTag(MessageTranslator.convertToJavaMessage(textTag.getValue())));
|
||||
}
|
||||
|
||||
itemTag.remove("pages");
|
||||
|
@ -45,15 +45,15 @@ public class CrossbowTranslator extends NbtItemStackTranslator {
|
||||
if (!chargedProjectiles.getValue().isEmpty()) {
|
||||
CompoundTag projectile = (CompoundTag) chargedProjectiles.getValue().get(0);
|
||||
|
||||
ItemEntry entry = ItemRegistry.getItemEntry((String) projectile.get("id").getValue());
|
||||
if (entry == null) return;
|
||||
ItemEntry projectileEntry = ItemRegistry.getItemEntry((String) projectile.get("id").getValue());
|
||||
if (projectileEntry == null) return;
|
||||
CompoundTag tag = projectile.get("tag");
|
||||
ItemStack itemStack = new ItemStack(itemEntry.getJavaId(), (byte) projectile.get("Count").getValue(), tag);
|
||||
ItemData itemData = ItemTranslator.translateToBedrock(session, itemStack);
|
||||
|
||||
CompoundTag newProjectile = new CompoundTag("chargedItem");
|
||||
newProjectile.put(new ByteTag("Count", (byte) itemData.getCount()));
|
||||
newProjectile.put(new StringTag("Name", ItemRegistry.getBedrockIdentifer(entry)));
|
||||
newProjectile.put(new StringTag("Name", projectileEntry.getBedrockIdentifier()));
|
||||
|
||||
newProjectile.put(new ShortTag("Damage", itemData.getDamage()));
|
||||
|
||||
|
@ -25,10 +25,7 @@
|
||||
|
||||
package org.geysermc.connector.network.translators.item.translators.nbt;
|
||||
|
||||
import com.github.steveice10.opennbt.tag.builtin.ByteTag;
|
||||
import com.github.steveice10.opennbt.tag.builtin.CompoundTag;
|
||||
import com.github.steveice10.opennbt.tag.builtin.IntTag;
|
||||
import com.github.steveice10.opennbt.tag.builtin.LongTag;
|
||||
import com.github.steveice10.opennbt.tag.builtin.*;
|
||||
import org.geysermc.connector.network.session.GeyserSession;
|
||||
import org.geysermc.connector.network.translators.ItemRemapper;
|
||||
import org.geysermc.connector.network.translators.item.ItemEntry;
|
||||
@ -39,15 +36,23 @@ public class MapItemTranslator extends NbtItemStackTranslator {
|
||||
|
||||
@Override
|
||||
public void translateToBedrock(GeyserSession session, CompoundTag itemTag, ItemEntry itemEntry) {
|
||||
IntTag mapId = itemTag.get("map");
|
||||
// Can be either an IntTag or ShortTag
|
||||
Tag mapId = itemTag.get("map");
|
||||
if (mapId == null) return;
|
||||
|
||||
if (mapId != null) {
|
||||
itemTag.put(new LongTag("map_uuid", mapId.getValue()));
|
||||
itemTag.put(new IntTag("map_name_index", mapId.getValue()));
|
||||
int mapValue;
|
||||
if (mapId.getValue() instanceof Short) {
|
||||
// Convert to int if necessary
|
||||
mapValue = (int) (short) mapId.getValue();
|
||||
} else {
|
||||
mapValue = (int) mapId.getValue();
|
||||
}
|
||||
|
||||
itemTag.put(new LongTag("map_uuid", mapValue));
|
||||
itemTag.put(new IntTag("map_name_index", mapValue));
|
||||
itemTag.put(new ByteTag("map_display_players", (byte) 1));
|
||||
itemTag.remove("map");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void translateToJava(CompoundTag itemTag, ItemEntry itemEntry) {
|
||||
|
@ -50,9 +50,8 @@ public class ShulkerBoxItemTranslator extends NbtItemStackTranslator {
|
||||
boxItemTag.put(new ByteTag("WasPickedUp", (byte) 0)); // ???
|
||||
|
||||
ItemEntry boxItemEntry = ItemRegistry.getItemEntry(((StringTag) itemData.get("id")).getValue());
|
||||
String blockName = ItemRegistry.getBedrockIdentifer(boxItemEntry);
|
||||
|
||||
boxItemTag.put(new StringTag("Name", blockName));
|
||||
boxItemTag.put(new StringTag("Name", boxItemEntry.getBedrockIdentifier()));
|
||||
boxItemTag.put(new ShortTag("Damage", (short) boxItemEntry.getBedrockData()));
|
||||
boxItemTag.put(new ByteTag("Count", ((ByteTag) itemData.get("Count")).getValue()));
|
||||
if (itemData.contains("tag")) {
|
||||
|
@ -25,15 +25,12 @@
|
||||
|
||||
package org.geysermc.connector.network.translators.java;
|
||||
|
||||
import com.github.steveice10.mc.protocol.data.message.TranslationMessage;
|
||||
import com.github.steveice10.mc.protocol.packet.ingame.server.ServerChatPacket;
|
||||
import com.nukkitx.protocol.bedrock.packet.TextPacket;
|
||||
import org.geysermc.connector.network.session.GeyserSession;
|
||||
import org.geysermc.connector.network.translators.PacketTranslator;
|
||||
import org.geysermc.connector.network.translators.Translator;
|
||||
import org.geysermc.connector.utils.MessageUtils;
|
||||
|
||||
import java.util.List;
|
||||
import org.geysermc.connector.network.translators.chat.MessageTranslator;
|
||||
|
||||
@Translator(packet = ServerChatPacket.class)
|
||||
public class JavaChatTranslator extends PacketTranslator<ServerChatPacket> {
|
||||
@ -59,21 +56,8 @@ public class JavaChatTranslator extends PacketTranslator<ServerChatPacket> {
|
||||
break;
|
||||
}
|
||||
|
||||
String locale = session.getLocale();
|
||||
|
||||
if (packet.getMessage() instanceof TranslationMessage) {
|
||||
textPacket.setType(TextPacket.Type.TRANSLATION);
|
||||
textPacket.setNeedsTranslation(true);
|
||||
|
||||
List<String> paramsTranslated = MessageUtils.getTranslationParams(((TranslationMessage) packet.getMessage()).getWith(), locale, packet.getMessage());
|
||||
textPacket.setParameters(paramsTranslated);
|
||||
|
||||
textPacket.setMessage(MessageUtils.insertParams(MessageUtils.getTranslatedBedrockMessage(packet.getMessage(), locale, true, packet.getMessage()), paramsTranslated));
|
||||
} else {
|
||||
textPacket.setNeedsTranslation(false);
|
||||
|
||||
textPacket.setMessage(MessageUtils.getTranslatedBedrockMessage(packet.getMessage(), locale, false, packet.getMessage()));
|
||||
}
|
||||
textPacket.setMessage(MessageTranslator.convertMessage(packet.getMessage().toString(), session.getLocale()));
|
||||
|
||||
session.sendUpstreamPacket(textPacket);
|
||||
}
|
||||
|
@ -29,13 +29,13 @@ import com.github.steveice10.mc.protocol.packet.ingame.server.ServerDisconnectPa
|
||||
import org.geysermc.connector.network.session.GeyserSession;
|
||||
import org.geysermc.connector.network.translators.PacketTranslator;
|
||||
import org.geysermc.connector.network.translators.Translator;
|
||||
import org.geysermc.connector.utils.MessageUtils;
|
||||
import org.geysermc.connector.network.translators.chat.MessageTranslator;
|
||||
|
||||
@Translator(packet = ServerDisconnectPacket.class)
|
||||
public class JavaDisconnectPacket extends PacketTranslator<ServerDisconnectPacket> {
|
||||
|
||||
@Override
|
||||
public void translate(ServerDisconnectPacket packet, GeyserSession session) {
|
||||
session.disconnect(MessageUtils.getTranslatedBedrockMessage(packet.getReason(), session.getLocale(), true));
|
||||
session.disconnect(MessageTranslator.convertMessage(packet.getReason().toString(), session.getLocale()));
|
||||
}
|
||||
}
|
||||
|
@ -55,7 +55,7 @@ public class JavaJoinGameTranslator extends PacketTranslator<ServerJoinGamePacke
|
||||
// are swapping servers
|
||||
String newDimension = DimensionUtils.getNewDimension(packet.getDimension());
|
||||
if (session.isSpawned()) {
|
||||
String fakeDim = entity.getDimension().equals(DimensionUtils.OVERWORLD) ? DimensionUtils.NETHER : DimensionUtils.OVERWORLD;
|
||||
String fakeDim = session.getDimension().equals(DimensionUtils.OVERWORLD) ? DimensionUtils.NETHER : DimensionUtils.OVERWORLD;
|
||||
DimensionUtils.switchDimension(session, fakeDim);
|
||||
DimensionUtils.switchDimension(session, newDimension);
|
||||
|
||||
@ -101,7 +101,7 @@ public class JavaJoinGameTranslator extends PacketTranslator<ServerJoinGamePacke
|
||||
session.sendDownstreamPacket(new ClientPluginMessagePacket("minecraft:register", PluginMessageUtils.getFloodgateRegisterData()));
|
||||
}
|
||||
|
||||
if (!newDimension.equals(entity.getDimension())) {
|
||||
if (!newDimension.equals(session.getDimension())) {
|
||||
DimensionUtils.switchDimension(session, newDimension);
|
||||
}
|
||||
}
|
||||
|
@ -29,7 +29,7 @@ import com.github.steveice10.mc.protocol.packet.login.server.LoginDisconnectPack
|
||||
import org.geysermc.connector.network.session.GeyserSession;
|
||||
import org.geysermc.connector.network.translators.PacketTranslator;
|
||||
import org.geysermc.connector.network.translators.Translator;
|
||||
import org.geysermc.connector.utils.MessageUtils;
|
||||
import org.geysermc.connector.network.translators.chat.MessageTranslator;
|
||||
|
||||
@Translator(packet = LoginDisconnectPacket.class)
|
||||
public class JavaLoginDisconnectTranslator extends PacketTranslator<LoginDisconnectPacket> {
|
||||
@ -37,6 +37,6 @@ public class JavaLoginDisconnectTranslator extends PacketTranslator<LoginDisconn
|
||||
@Override
|
||||
public void translate(LoginDisconnectPacket packet, GeyserSession session) {
|
||||
// The client doesn't manually get disconnected so we have to do it ourselves
|
||||
session.disconnect(MessageUtils.getTranslatedBedrockMessage(packet.getReason(), session.getLocale()));
|
||||
session.disconnect(MessageTranslator.convertMessage(packet.getReason().toString(), session.getLocale()));
|
||||
}
|
||||
}
|
||||
|
@ -67,11 +67,11 @@ public class JavaRespawnTranslator extends PacketTranslator<ServerRespawnPacket>
|
||||
}
|
||||
|
||||
String newDimension = DimensionUtils.getNewDimension(packet.getDimension());
|
||||
if (!entity.getDimension().equals(newDimension)) {
|
||||
if (!session.getDimension().equals(newDimension)) {
|
||||
DimensionUtils.switchDimension(session, newDimension);
|
||||
} else {
|
||||
if (session.isManyDimPackets()) { //reloading world
|
||||
String fakeDim = entity.getDimension().equals(DimensionUtils.OVERWORLD) ? DimensionUtils.NETHER : DimensionUtils.OVERWORLD;
|
||||
String fakeDim = session.getDimension().equals(DimensionUtils.OVERWORLD) ? DimensionUtils.NETHER : DimensionUtils.OVERWORLD;
|
||||
DimensionUtils.switchDimension(session, fakeDim);
|
||||
DimensionUtils.switchDimension(session, newDimension);
|
||||
} else {
|
||||
|
@ -28,7 +28,7 @@ package org.geysermc.connector.network.translators.java;
|
||||
import org.geysermc.connector.network.session.GeyserSession;
|
||||
import org.geysermc.connector.network.translators.PacketTranslator;
|
||||
import org.geysermc.connector.network.translators.Translator;
|
||||
import org.geysermc.connector.utils.MessageUtils;
|
||||
import org.geysermc.connector.network.translators.chat.MessageTranslator;
|
||||
|
||||
import com.github.steveice10.mc.protocol.packet.ingame.server.ServerTitlePacket;
|
||||
import com.nukkitx.protocol.bedrock.packet.SetTitlePacket;
|
||||
@ -41,14 +41,21 @@ public class JavaTitleTranslator extends PacketTranslator<ServerTitlePacket> {
|
||||
SetTitlePacket titlePacket = new SetTitlePacket();
|
||||
String locale = session.getLocale();
|
||||
|
||||
String text;
|
||||
if (packet.getTitle() == null) {
|
||||
text = " ";
|
||||
} else {
|
||||
text = MessageTranslator.convertMessage(packet.getTitle().toString(), locale);
|
||||
}
|
||||
|
||||
switch (packet.getAction()) {
|
||||
case TITLE:
|
||||
titlePacket.setType(SetTitlePacket.Type.TITLE);
|
||||
titlePacket.setText(MessageUtils.getTranslatedBedrockMessage(packet.getTitle(), locale));
|
||||
titlePacket.setText(text);
|
||||
break;
|
||||
case SUBTITLE:
|
||||
titlePacket.setType(SetTitlePacket.Type.SUBTITLE);
|
||||
titlePacket.setText(MessageUtils.getTranslatedBedrockMessage(packet.getTitle(), locale));
|
||||
titlePacket.setText(text);
|
||||
break;
|
||||
case CLEAR:
|
||||
case RESET:
|
||||
@ -57,9 +64,10 @@ public class JavaTitleTranslator extends PacketTranslator<ServerTitlePacket> {
|
||||
break;
|
||||
case ACTION_BAR:
|
||||
titlePacket.setType(SetTitlePacket.Type.ACTIONBAR);
|
||||
titlePacket.setText(MessageUtils.getTranslatedBedrockMessage(packet.getTitle(), locale));
|
||||
titlePacket.setText(text);
|
||||
break;
|
||||
case TIMES:
|
||||
titlePacket.setType(SetTitlePacket.Type.TIMES);
|
||||
titlePacket.setFadeInTime(packet.getFadeIn());
|
||||
titlePacket.setFadeOutTime(packet.getFadeOut());
|
||||
titlePacket.setStayTime(packet.getStay());
|
||||
|
@ -62,7 +62,7 @@ public class JavaEntityAttachTranslator extends PacketTranslator<ServerEntityAtt
|
||||
if ((attachedToId == null || packet.getAttachedToId() == 0)) {
|
||||
// Is not being leashed
|
||||
holderId.getMetadata().getFlags().setFlag(EntityFlag.LEASHED, false);
|
||||
holderId.getMetadata().put(EntityData.LEASH_HOLDER_EID, 0);
|
||||
holderId.getMetadata().put(EntityData.LEASH_HOLDER_EID, -1L);
|
||||
holderId.updateBedrockMetadata(session);
|
||||
EntityEventPacket eventPacket = new EntityEventPacket();
|
||||
eventPacket.setRuntimeEntityId(holderId.getGeyserId());
|
||||
|
@ -33,6 +33,8 @@ import com.nukkitx.protocol.bedrock.data.entity.EntityLinkData;
|
||||
import com.nukkitx.protocol.bedrock.packet.SetEntityLinkPacket;
|
||||
import it.unimi.dsi.fastutil.longs.LongOpenHashSet;
|
||||
import org.geysermc.connector.entity.Entity;
|
||||
import org.geysermc.connector.entity.living.ArmorStandEntity;
|
||||
import org.geysermc.connector.entity.living.animal.AnimalEntity;
|
||||
import org.geysermc.connector.entity.type.EntityType;
|
||||
import org.geysermc.connector.network.session.GeyserSession;
|
||||
import org.geysermc.connector.network.translators.PacketTranslator;
|
||||
@ -46,6 +48,10 @@ public class JavaEntitySetPassengersTranslator extends PacketTranslator<ServerEn
|
||||
@Override
|
||||
public void translate(ServerEntitySetPassengersPacket packet, GeyserSession session) {
|
||||
Entity entity = session.getEntityCache().getEntityByJavaId(packet.getEntityId());
|
||||
if (packet.getEntityId() == session.getPlayerEntity().getEntityId()) {
|
||||
entity = session.getPlayerEntity();
|
||||
}
|
||||
|
||||
if (entity == null) return;
|
||||
|
||||
LongOpenHashSet passengers = entity.getPassengers().clone();
|
||||
@ -123,19 +129,19 @@ public class JavaEntitySetPassengersTranslator extends PacketTranslator<ServerEn
|
||||
}
|
||||
|
||||
private float getMountedHeightOffset(Entity mount) {
|
||||
final EntityType mountType = mount.getEntityType();
|
||||
float mountedHeightOffset = mountType.getHeight() * 0.75f;
|
||||
switch (mountType) {
|
||||
float height = mount.getMetadata().getFloat(EntityData.BOUNDING_BOX_HEIGHT);
|
||||
float mountedHeightOffset = height * 0.75f;
|
||||
switch (mount.getEntityType()) {
|
||||
case CHICKEN:
|
||||
case SPIDER:
|
||||
mountedHeightOffset = mountType.getHeight() * 0.5f;
|
||||
mountedHeightOffset = height * 0.5f;
|
||||
break;
|
||||
case DONKEY:
|
||||
case MULE:
|
||||
mountedHeightOffset -= 0.25f;
|
||||
break;
|
||||
case LLAMA:
|
||||
mountedHeightOffset = mountType.getHeight() * 0.67f;
|
||||
mountedHeightOffset = height * 0.67f;
|
||||
break;
|
||||
case MINECART:
|
||||
case MINECART_HOPPER:
|
||||
@ -152,10 +158,10 @@ public class JavaEntitySetPassengersTranslator extends PacketTranslator<ServerEn
|
||||
case HOGLIN:
|
||||
case ZOGLIN:
|
||||
boolean isBaby = mount.getMetadata().getFlags().getFlag(EntityFlag.BABY);
|
||||
mountedHeightOffset = mountType.getHeight() - (isBaby ? 0.2f : 0.15f);
|
||||
mountedHeightOffset = height - (isBaby ? 0.2f : 0.15f);
|
||||
break;
|
||||
case PIGLIN:
|
||||
mountedHeightOffset = mountType.getHeight() * 0.92f;
|
||||
mountedHeightOffset = height * 0.92f;
|
||||
break;
|
||||
case RAVAGER:
|
||||
mountedHeightOffset = 2.1f;
|
||||
@ -164,7 +170,7 @@ public class JavaEntitySetPassengersTranslator extends PacketTranslator<ServerEn
|
||||
mountedHeightOffset -= 0.1875f;
|
||||
break;
|
||||
case STRIDER:
|
||||
mountedHeightOffset = mountType.getHeight() - 0.19f;
|
||||
mountedHeightOffset = height - 0.19f;
|
||||
break;
|
||||
}
|
||||
return mountedHeightOffset;
|
||||
@ -178,11 +184,10 @@ public class JavaEntitySetPassengersTranslator extends PacketTranslator<ServerEn
|
||||
case WITHER_SKELETON:
|
||||
return -0.6f;
|
||||
case ARMOR_STAND:
|
||||
// Armor stand isn't a marker
|
||||
if (passenger.getMetadata().getFloat(EntityData.BOUNDING_BOX_HEIGHT) != 0.0f) {
|
||||
return 0.1f;
|
||||
} else {
|
||||
if (((ArmorStandEntity) passenger).isMarker()) {
|
||||
return 0.0f;
|
||||
} else {
|
||||
return 0.1f;
|
||||
}
|
||||
case ENDERMITE:
|
||||
case SILVERFISH:
|
||||
@ -205,6 +210,9 @@ public class JavaEntitySetPassengersTranslator extends PacketTranslator<ServerEn
|
||||
case PLAYER:
|
||||
return -0.35f;
|
||||
}
|
||||
if (passenger instanceof AnimalEntity) {
|
||||
return 0.14f;
|
||||
}
|
||||
return 0f;
|
||||
}
|
||||
|
||||
@ -240,7 +248,7 @@ public class JavaEntitySetPassengersTranslator extends PacketTranslator<ServerEn
|
||||
* Horses are tinier
|
||||
* Players, Minecarts, and Boats have different origins
|
||||
*/
|
||||
if (passenger.getEntityType() == EntityType.PLAYER) {
|
||||
if (passenger.getEntityType() == EntityType.PLAYER && mount.getEntityType() != EntityType.PLAYER) {
|
||||
yOffset += EntityType.PLAYER.getOffset();
|
||||
}
|
||||
switch (mount.getEntityType()) {
|
||||
|
@ -25,15 +25,13 @@
|
||||
|
||||
package org.geysermc.connector.network.translators.java.entity;
|
||||
|
||||
import com.github.steveice10.mc.protocol.data.game.entity.metadata.ItemStack;
|
||||
import com.github.steveice10.mc.protocol.data.game.world.particle.ItemParticleData;
|
||||
import com.github.steveice10.mc.protocol.packet.ingame.server.entity.ServerEntityStatusPacket;
|
||||
import com.nukkitx.math.vector.Vector3f;
|
||||
import com.nukkitx.protocol.bedrock.data.SoundEvent;
|
||||
import com.nukkitx.protocol.bedrock.data.LevelEventType;
|
||||
import com.nukkitx.protocol.bedrock.data.entity.EntityData;
|
||||
import com.nukkitx.protocol.bedrock.data.entity.EntityEventType;
|
||||
import com.nukkitx.protocol.bedrock.data.inventory.ItemData;
|
||||
import com.nukkitx.protocol.bedrock.packet.EntityEventPacket;
|
||||
import com.nukkitx.protocol.bedrock.packet.LevelSoundEvent2Packet;
|
||||
import com.nukkitx.protocol.bedrock.packet.LevelEventPacket;
|
||||
import com.nukkitx.protocol.bedrock.packet.SetEntityDataPacket;
|
||||
import com.nukkitx.protocol.bedrock.packet.SetEntityMotionPacket;
|
||||
@ -42,9 +40,7 @@ import org.geysermc.connector.entity.type.EntityType;
|
||||
import org.geysermc.connector.network.session.GeyserSession;
|
||||
import org.geysermc.connector.network.translators.PacketTranslator;
|
||||
import org.geysermc.connector.network.translators.Translator;
|
||||
import org.geysermc.connector.network.translators.item.ItemEntry;
|
||||
import org.geysermc.connector.network.translators.item.ItemRegistry;
|
||||
import org.geysermc.connector.network.translators.item.ItemTranslator;
|
||||
|
||||
@Translator(packet = ServerEntityStatusPacket.class)
|
||||
public class JavaEntityStatusTranslator extends PacketTranslator<ServerEntityStatusPacket> {
|
||||
@ -141,9 +137,15 @@ public class JavaEntityStatusTranslator extends PacketTranslator<ServerEntitySta
|
||||
case TAMEABLE_TAMING_SUCCEEDED:
|
||||
entityEventPacket.setType(EntityEventType.TAME_SUCCEEDED);
|
||||
break;
|
||||
case ZOMBIE_VILLAGER_CURE:
|
||||
entityEventPacket.setType(EntityEventType.ZOMBIE_VILLAGER_CURE);
|
||||
break;
|
||||
case ZOMBIE_VILLAGER_CURE: // Played when a zombie bites the golden apple
|
||||
LevelSoundEvent2Packet soundPacket = new LevelSoundEvent2Packet();
|
||||
soundPacket.setSound(SoundEvent.REMEDY);
|
||||
soundPacket.setPosition(entity.getPosition());
|
||||
soundPacket.setExtraData(-1);
|
||||
soundPacket.setIdentifier("");
|
||||
soundPacket.setRelativeVolumeDisabled(false);
|
||||
session.sendUpstreamPacket(soundPacket);
|
||||
return;
|
||||
case ANIMAL_EMIT_HEARTS:
|
||||
entityEventPacket.setType(EntityEventType.LOVE_PARTICLES);
|
||||
break;
|
||||
|
@ -43,7 +43,12 @@ public class JavaSpawnPlayerTranslator extends PacketTranslator<ServerSpawnPlaye
|
||||
Vector3f position = Vector3f.from(packet.getX(), packet.getY(), packet.getZ());
|
||||
Vector3f rotation = Vector3f.from(packet.getYaw(), packet.getPitch(), packet.getYaw());
|
||||
|
||||
PlayerEntity entity = session.getEntityCache().getPlayerEntity(packet.getUuid());
|
||||
PlayerEntity entity;
|
||||
if (packet.getUuid().equals(session.getPlayerEntity().getUuid())) {
|
||||
// Server is sending a fake version of the current player
|
||||
entity = new PlayerEntity(session.getPlayerEntity().getProfile(), packet.getEntityId(), session.getEntityCache().getNextEntityId().incrementAndGet(), position, Vector3f.ZERO, rotation);
|
||||
} else {
|
||||
entity = session.getEntityCache().getPlayerEntity(packet.getUuid());
|
||||
if (entity == null) {
|
||||
GeyserConnector.getInstance().getLogger().error(LanguageUtils.getLocaleStringLog("geyser.entity.player.failed_list", packet.getUuid()));
|
||||
return;
|
||||
@ -52,6 +57,7 @@ public class JavaSpawnPlayerTranslator extends PacketTranslator<ServerSpawnPlaye
|
||||
entity.setEntityId(packet.getEntityId());
|
||||
entity.setPosition(position);
|
||||
entity.setRotation(rotation);
|
||||
}
|
||||
session.getEntityCache().cacheEntity(entity);
|
||||
|
||||
if (session.getUpstream().isInitialized()) {
|
||||
|
@ -36,8 +36,7 @@ public class JavaDisplayScoreboardTranslator extends PacketTranslator<ServerDisp
|
||||
|
||||
@Override
|
||||
public void translate(ServerDisplayScoreboardPacket packet, GeyserSession session) {
|
||||
session.getWorldCache().getScoreboard().registerNewObjective(
|
||||
packet.getName(), packet.getPosition()
|
||||
);
|
||||
session.getWorldCache().getScoreboard()
|
||||
.displayObjective(packet.getName(), packet.getPosition());
|
||||
}
|
||||
}
|
||||
|
@ -31,7 +31,8 @@ import org.geysermc.connector.network.translators.PacketTranslator;
|
||||
import org.geysermc.connector.network.translators.Translator;
|
||||
import org.geysermc.connector.scoreboard.Objective;
|
||||
import org.geysermc.connector.scoreboard.Scoreboard;
|
||||
import org.geysermc.connector.utils.MessageUtils;
|
||||
import org.geysermc.connector.scoreboard.ScoreboardUpdater;
|
||||
import org.geysermc.connector.network.translators.chat.MessageTranslator;
|
||||
|
||||
import com.github.steveice10.mc.protocol.data.game.scoreboard.ObjectiveAction;
|
||||
import com.github.steveice10.mc.protocol.packet.ingame.server.scoreboard.ServerScoreboardObjectivePacket;
|
||||
@ -41,8 +42,10 @@ public class JavaScoreboardObjectiveTranslator extends PacketTranslator<ServerSc
|
||||
|
||||
@Override
|
||||
public void translate(ServerScoreboardObjectivePacket packet, GeyserSession session) {
|
||||
Scoreboard scoreboard = session.getWorldCache().getScoreboard();
|
||||
WorldCache worldCache = session.getWorldCache();
|
||||
Scoreboard scoreboard = worldCache.getScoreboard();
|
||||
Objective objective = scoreboard.getObjective(packet.getName());
|
||||
int pps = worldCache.increaseAndGetScoreboardPacketsPerSecond();
|
||||
|
||||
if (objective == null && packet.getAction() != ObjectiveAction.REMOVE) {
|
||||
objective = scoreboard.registerNewObjective(packet.getName(), false);
|
||||
@ -51,15 +54,21 @@ public class JavaScoreboardObjectiveTranslator extends PacketTranslator<ServerSc
|
||||
switch (packet.getAction()) {
|
||||
case ADD:
|
||||
case UPDATE:
|
||||
objective.setDisplayName(MessageUtils.getBedrockMessage(packet.getDisplayName()));
|
||||
objective.setType(packet.getType().ordinal());
|
||||
objective.setDisplayName(MessageTranslator.convertMessage(packet.getDisplayName().toString()))
|
||||
.setType(packet.getType().ordinal());
|
||||
break;
|
||||
case REMOVE:
|
||||
scoreboard.unregisterObjective(packet.getName());
|
||||
break;
|
||||
}
|
||||
|
||||
if (objective != null && objective.isActive()) {
|
||||
if (objective == null || !objective.isActive()) {
|
||||
return;
|
||||
}
|
||||
|
||||
// ScoreboardUpdater will handle it for us if the packets per second
|
||||
// (for score and team packets) is higher then the first threshold
|
||||
if (pps < ScoreboardUpdater.FIRST_SCORE_PACKETS_PER_SECOND_THRESHOLD) {
|
||||
scoreboard.onUpdate();
|
||||
}
|
||||
}
|
||||
|
@ -37,7 +37,7 @@ import org.geysermc.connector.scoreboard.ScoreboardUpdater;
|
||||
import org.geysermc.connector.scoreboard.Team;
|
||||
import org.geysermc.connector.scoreboard.UpdateType;
|
||||
import org.geysermc.connector.utils.LanguageUtils;
|
||||
import org.geysermc.connector.utils.MessageUtils;
|
||||
import org.geysermc.connector.network.translators.chat.MessageTranslator;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Set;
|
||||
@ -59,11 +59,11 @@ public class JavaTeamTranslator extends PacketTranslator<ServerTeamPacket> {
|
||||
switch (packet.getAction()) {
|
||||
case CREATE:
|
||||
scoreboard.registerNewTeam(packet.getTeamName(), toPlayerSet(packet.getPlayers()))
|
||||
.setName(MessageUtils.getBedrockMessage(packet.getDisplayName()))
|
||||
.setName(MessageTranslator.convertMessage(packet.getDisplayName().toString()))
|
||||
.setColor(packet.getColor())
|
||||
.setNameTagVisibility(packet.getNameTagVisibility())
|
||||
.setPrefix(MessageUtils.getTranslatedBedrockMessage(packet.getPrefix(), session.getLocale()))
|
||||
.setSuffix(MessageUtils.getTranslatedBedrockMessage(packet.getSuffix(), session.getLocale()));
|
||||
.setPrefix(MessageTranslator.convertMessage(packet.getPrefix().toString(), session.getLocale()))
|
||||
.setSuffix(MessageTranslator.convertMessage(packet.getSuffix().toString(), session.getLocale()));
|
||||
break;
|
||||
case UPDATE:
|
||||
if (team == null) {
|
||||
@ -74,11 +74,11 @@ public class JavaTeamTranslator extends PacketTranslator<ServerTeamPacket> {
|
||||
return;
|
||||
}
|
||||
|
||||
team.setName(MessageUtils.getBedrockMessage(packet.getDisplayName()))
|
||||
team.setName(MessageTranslator.convertMessage(packet.getDisplayName().toString()))
|
||||
.setColor(packet.getColor())
|
||||
.setNameTagVisibility(packet.getNameTagVisibility())
|
||||
.setPrefix(MessageUtils.getTranslatedBedrockMessage(packet.getPrefix(), session.getLocale()))
|
||||
.setSuffix(MessageUtils.getTranslatedBedrockMessage(packet.getSuffix(), session.getLocale()))
|
||||
.setPrefix(MessageTranslator.convertMessage(packet.getPrefix().toString(), session.getLocale()))
|
||||
.setSuffix(MessageTranslator.convertMessage(packet.getSuffix().toString(), session.getLocale()))
|
||||
.setUpdateType(UpdateType.UPDATE);
|
||||
break;
|
||||
case ADD_PLAYER:
|
||||
|
@ -25,7 +25,6 @@
|
||||
|
||||
package org.geysermc.connector.network.translators.java.window;
|
||||
|
||||
import com.github.steveice10.mc.protocol.data.message.MessageSerializer;
|
||||
import com.github.steveice10.mc.protocol.packet.ingame.client.window.ClientCloseWindowPacket;
|
||||
import com.github.steveice10.mc.protocol.packet.ingame.server.window.ServerOpenWindowPacket;
|
||||
import org.geysermc.connector.inventory.Inventory;
|
||||
@ -35,7 +34,7 @@ import org.geysermc.connector.network.translators.Translator;
|
||||
import org.geysermc.connector.network.translators.inventory.InventoryTranslator;
|
||||
import org.geysermc.connector.utils.InventoryUtils;
|
||||
import org.geysermc.connector.utils.LocaleUtils;
|
||||
import org.geysermc.connector.utils.MessageUtils;
|
||||
import org.geysermc.connector.network.translators.chat.MessageTranslator;
|
||||
|
||||
@Translator(packet = ServerOpenWindowPacket.class)
|
||||
public class JavaOpenWindowTranslator extends PacketTranslator<ServerOpenWindowPacket> {
|
||||
@ -57,8 +56,7 @@ public class JavaOpenWindowTranslator extends PacketTranslator<ServerOpenWindowP
|
||||
return;
|
||||
}
|
||||
|
||||
String name = MessageUtils.getTranslatedBedrockMessage(MessageSerializer.fromString(packet.getName()),
|
||||
session.getLocale());
|
||||
String name = MessageTranslator.convertMessageLenient(packet.getName(), session.getLocale());
|
||||
|
||||
name = LocaleUtils.getLocaleString(name, session.getLocale());
|
||||
|
||||
|
@ -29,7 +29,7 @@ import com.github.steveice10.mc.protocol.data.game.entity.metadata.Position;
|
||||
import com.nukkitx.math.vector.Vector3i;
|
||||
import com.nukkitx.protocol.bedrock.data.SoundEvent;
|
||||
import com.nukkitx.protocol.bedrock.packet.LevelSoundEventPacket;
|
||||
import org.geysermc.connector.common.PlatformType;
|
||||
import org.geysermc.common.PlatformType;
|
||||
import org.geysermc.connector.network.session.GeyserSession;
|
||||
import org.geysermc.connector.network.translators.PacketTranslator;
|
||||
import org.geysermc.connector.network.translators.Translator;
|
||||
|
@ -25,6 +25,7 @@
|
||||
|
||||
package org.geysermc.connector.network.translators.java.world;
|
||||
|
||||
import com.github.steveice10.mc.protocol.data.game.entity.metadata.Position;
|
||||
import com.github.steveice10.mc.protocol.data.game.world.block.value.*;
|
||||
import com.github.steveice10.mc.protocol.packet.ingame.server.world.ServerBlockValuePacket;
|
||||
import com.nukkitx.math.vector.Vector3i;
|
||||
@ -53,16 +54,12 @@ public class JavaBlockValueTranslator extends PacketTranslator<ServerBlockValueP
|
||||
blockEventPacket.setEventType(1);
|
||||
blockEventPacket.setEventData(value.getViewers() > 0 ? 1 : 0);
|
||||
session.sendUpstreamPacket(blockEventPacket);
|
||||
}
|
||||
if (packet.getValue() instanceof EndGatewayValue) {
|
||||
} else if (packet.getValue() instanceof EndGatewayValue) {
|
||||
blockEventPacket.setEventType(1);
|
||||
session.sendUpstreamPacket(blockEventPacket);
|
||||
}
|
||||
if (packet.getValue() instanceof NoteBlockValue) {
|
||||
} else if (packet.getValue() instanceof NoteBlockValue) {
|
||||
NoteblockBlockEntityTranslator.translate(session, packet.getPosition());
|
||||
return;
|
||||
}
|
||||
if (packet.getValue() instanceof PistonValue) {
|
||||
} else if (packet.getValue() instanceof PistonValue) {
|
||||
PistonValueType type = (PistonValueType) packet.getType();
|
||||
|
||||
// Unlike everything else, pistons need a block entity packet to convey motion
|
||||
@ -73,14 +70,46 @@ public class JavaBlockValueTranslator extends PacketTranslator<ServerBlockValueP
|
||||
} else {
|
||||
retractPiston(session, position, 1.0f, 1.0f);
|
||||
}
|
||||
}
|
||||
if (packet.getValue() instanceof MobSpawnerValue) {
|
||||
} else if (packet.getValue() instanceof MobSpawnerValue) {
|
||||
blockEventPacket.setEventType(1);
|
||||
session.sendUpstreamPacket(blockEventPacket);
|
||||
}
|
||||
if (packet.getValue() instanceof EndGatewayValue) {
|
||||
} else if (packet.getValue() instanceof EndGatewayValue) {
|
||||
blockEventPacket.setEventType(1);
|
||||
session.sendUpstreamPacket(blockEventPacket);
|
||||
} else if (packet.getValue() instanceof GenericBlockValue && packet.getBlockId() == 677) {
|
||||
// TODO: Remove hardcode? Remove hardcodes for all of these? (EndGatewayValue for example still hardcodes the block)
|
||||
// Bells - needed to show ring from other players
|
||||
GenericBlockValue bellValue = (GenericBlockValue) packet.getValue();
|
||||
Position position = packet.getPosition();
|
||||
|
||||
BlockEntityDataPacket blockEntityPacket = new BlockEntityDataPacket();
|
||||
blockEntityPacket.setBlockPosition(Vector3i.from(position.getX(), position.getY(), position.getZ()));
|
||||
|
||||
NbtMapBuilder builder = NbtMap.builder();
|
||||
builder.putInt("x", position.getX());
|
||||
builder.putInt("y", position.getY());
|
||||
builder.putInt("z", position.getZ());
|
||||
builder.putString("id", "Bell");
|
||||
int bedrockRingDirection;
|
||||
switch (bellValue.getValue()) {
|
||||
case 3: // north
|
||||
bedrockRingDirection = 0;
|
||||
break;
|
||||
case 4: // east
|
||||
bedrockRingDirection = 1;
|
||||
break;
|
||||
case 5: // west
|
||||
bedrockRingDirection = 3;
|
||||
break;
|
||||
default: // south (2) is identical
|
||||
bedrockRingDirection = bellValue.getValue();
|
||||
}
|
||||
builder.putInt("Direction", bedrockRingDirection);
|
||||
builder.putByte("Ringing", (byte) 1);
|
||||
builder.putInt("Ticks", 0);
|
||||
|
||||
blockEntityPacket.setData(builder.build());
|
||||
session.sendUpstreamPacket(blockEntityPacket);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -45,14 +45,13 @@ import org.geysermc.connector.utils.ChunkUtils;
|
||||
|
||||
@Translator(packet = ServerChunkDataPacket.class)
|
||||
public class JavaChunkDataTranslator extends PacketTranslator<ServerChunkDataPacket> {
|
||||
|
||||
/**
|
||||
* Determines if we should process non-full chunks
|
||||
*/
|
||||
private final boolean isCacheChunks;
|
||||
private final boolean cacheChunks;
|
||||
|
||||
public JavaChunkDataTranslator() {
|
||||
isCacheChunks = GeyserConnector.getInstance().getConfig().isCacheChunks();
|
||||
cacheChunks = GeyserConnector.getInstance().getConfig().isCacheChunks();
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -61,7 +60,7 @@ public class JavaChunkDataTranslator extends PacketTranslator<ServerChunkDataPac
|
||||
ChunkUtils.updateChunkPosition(session, session.getPlayerEntity().getPosition().toInt());
|
||||
}
|
||||
|
||||
if (packet.getColumn().getBiomeData() == null && !isCacheChunks) {
|
||||
if (packet.getColumn().getBiomeData() == null && !cacheChunks) {
|
||||
// Non-full chunk without chunk caching
|
||||
session.getConnector().getLogger().debug("Not sending non-full chunk because chunk caching is off.");
|
||||
return;
|
||||
|
@ -46,7 +46,7 @@ public class JavaExplosionTranslator extends PacketTranslator<ServerExplosionPac
|
||||
public void translate(ServerExplosionPacket packet, GeyserSession session) {
|
||||
for (ExplodedBlockRecord record : packet.getExploded()) {
|
||||
Vector3f pos = Vector3f.from(packet.getX() + record.getX(), packet.getY() + record.getY(), packet.getZ() + record.getZ());
|
||||
ChunkUtils.updateBlock(session, BlockTranslator.AIR, pos.toInt());
|
||||
ChunkUtils.updateBlock(session, BlockTranslator.JAVA_AIR_ID, pos.toInt());
|
||||
}
|
||||
|
||||
Vector3f pos = Vector3f.from(packet.getX(), packet.getY(), packet.getZ());
|
||||
|
Einige Dateien werden nicht angezeigt, da zu viele Dateien in diesem Diff geändert wurden Mehr anzeigen
Laden…
In neuem Issue referenzieren
Einen Benutzer sperren