mirror of
https://github.com/GeyserMC/Geyser.git
synced 2024-08-14 23:57:35 +00:00
The Great Refactor Part 1 - connector -> core
This commit is contained in:
parent
a4b2e05132
commit
0b5009b415
573 changed files with 135 additions and 135 deletions
362
core/pom.xml
Normal file
362
core/pom.xml
Normal file
|
|
@ -0,0 +1,362 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<parent>
|
||||
<groupId>org.geysermc</groupId>
|
||||
<artifactId>geyser-parent</artifactId>
|
||||
<version>1.4.3-SNAPSHOT</version>
|
||||
</parent>
|
||||
<artifactId>core</artifactId>
|
||||
|
||||
<properties>
|
||||
<adventure.version>4.9.3</adventure.version>
|
||||
<fastutil.version>8.5.2</fastutil.version>
|
||||
<jackson.version>2.12.4</jackson.version>
|
||||
<netty.version>4.1.66.Final</netty.version>
|
||||
</properties>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.geysermc</groupId>
|
||||
<artifactId>ap</artifactId>
|
||||
<version>1.4.3-SNAPSHOT</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.geysermc</groupId>
|
||||
<artifactId>common</artifactId>
|
||||
<version>1.4.3-SNAPSHOT</version>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
<!-- Jackson JSON and YAML serialization -->
|
||||
<dependency>
|
||||
<groupId>com.fasterxml.jackson.core</groupId>
|
||||
<artifactId>jackson-annotations</artifactId>
|
||||
<version>${jackson.version}</version>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.fasterxml.jackson.core</groupId>
|
||||
<artifactId>jackson-core</artifactId>
|
||||
<version>${jackson.version}</version>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.fasterxml.jackson.core</groupId>
|
||||
<artifactId>jackson-databind</artifactId>
|
||||
<version>${jackson.version}</version>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.fasterxml.jackson.dataformat</groupId>
|
||||
<artifactId>jackson-dataformat-yaml</artifactId>
|
||||
<version>${jackson.version}</version>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.google.guava</groupId>
|
||||
<artifactId>guava</artifactId>
|
||||
<version>29.0-jre</version>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
<!-- fastutil maps -->
|
||||
<dependency>
|
||||
<groupId>com.nukkitx</groupId>
|
||||
<artifactId>nbt</artifactId>
|
||||
<!-- Used for key/value interning -->
|
||||
<version>2.1.0</version>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.nukkitx.fastutil</groupId>
|
||||
<artifactId>fastutil-int-int-maps</artifactId>
|
||||
<version>${fastutil.version}</version>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.nukkitx.fastutil</groupId>
|
||||
<artifactId>fastutil-long-long-maps</artifactId>
|
||||
<version>${fastutil.version}</version>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.nukkitx.fastutil</groupId>
|
||||
<artifactId>fastutil-int-byte-maps</artifactId>
|
||||
<version>${fastutil.version}</version>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.nukkitx.fastutil</groupId>
|
||||
<artifactId>fastutil-int-boolean-maps</artifactId>
|
||||
<version>${fastutil.version}</version>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.nukkitx.fastutil</groupId>
|
||||
<artifactId>fastutil-object-int-maps</artifactId>
|
||||
<version>${fastutil.version}</version>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.nukkitx.fastutil</groupId>
|
||||
<artifactId>fastutil-object-object-maps</artifactId>
|
||||
<version>${fastutil.version}</version>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
<!-- Network libraries -->
|
||||
<dependency>
|
||||
<groupId>org.java-websocket</groupId>
|
||||
<artifactId>Java-WebSocket</artifactId>
|
||||
<version>1.5.1</version>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.github.CloudburstMC.Protocol</groupId>
|
||||
<artifactId>bedrock-v475</artifactId>
|
||||
<version>c22aa595</version>
|
||||
<scope>compile</scope>
|
||||
<exclusions>
|
||||
<exclusion>
|
||||
<groupId>com.nukkitx.network</groupId>
|
||||
<artifactId>raknet</artifactId>
|
||||
</exclusion>
|
||||
<exclusion>
|
||||
<groupId>com.nukkitx</groupId>
|
||||
<artifactId>nbt</artifactId>
|
||||
</exclusion>
|
||||
</exclusions>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.nukkitx.network</groupId>
|
||||
<artifactId>raknet</artifactId>
|
||||
<version>1.6.27-20210506.111625-1</version>
|
||||
<scope>compile</scope>
|
||||
<exclusions>
|
||||
<exclusion>
|
||||
<groupId>io.netty</groupId>
|
||||
<artifactId>*</artifactId>
|
||||
</exclusion>
|
||||
</exclusions>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.github.RednedEpic</groupId>
|
||||
<artifactId>MCAuthLib</artifactId>
|
||||
<version>6c99331</version>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.github.steveice10</groupId>
|
||||
<artifactId>mcprotocollib</artifactId>
|
||||
<version>1.18-pre-SNAPSHOT</version>
|
||||
<scope>compile</scope>
|
||||
<exclusions>
|
||||
<exclusion>
|
||||
<groupId>com.github.steveice10</groupId>
|
||||
<artifactId>packetlib</artifactId>
|
||||
</exclusion>
|
||||
<exclusion>
|
||||
<groupId>com.github.steveice10</groupId>
|
||||
<artifactId>mcauthlib</artifactId>
|
||||
</exclusion>
|
||||
</exclusions>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.github.steveice10</groupId>
|
||||
<artifactId>packetlib</artifactId>
|
||||
<version>2.1-SNAPSHOT</version>
|
||||
<scope>compile</scope>
|
||||
<exclusions>
|
||||
<exclusion>
|
||||
<groupId>io.netty</groupId>
|
||||
<artifactId>netty-all</artifactId>
|
||||
</exclusion>
|
||||
<exclusion>
|
||||
<!-- This is still experimental - additionally, it could only really benefit standalone -->
|
||||
<groupId>io.netty.incubator</groupId>
|
||||
<artifactId>netty-incubator-transport-native-io_uring</artifactId>
|
||||
</exclusion>
|
||||
</exclusions>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>io.netty</groupId>
|
||||
<artifactId>netty-resolver-dns</artifactId>
|
||||
<version>${netty.version}</version>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>io.netty</groupId>
|
||||
<artifactId>netty-resolver-dns-native-macos</artifactId>
|
||||
<version>${netty.version}</version>
|
||||
<scope>compile</scope>
|
||||
<classifier>osx-x86_64</classifier>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>io.netty</groupId>
|
||||
<artifactId>netty-codec-haproxy</artifactId>
|
||||
<version>${netty.version}</version>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
<!-- Network dependencies we are updating ourselves -->
|
||||
<dependency>
|
||||
<groupId>io.netty</groupId>
|
||||
<artifactId>netty-handler</artifactId>
|
||||
<version>${netty.version}</version>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>io.netty</groupId>
|
||||
<artifactId>netty-transport-native-epoll</artifactId>
|
||||
<version>${netty.version}</version>
|
||||
<scope>compile</scope>
|
||||
<classifier>linux-x86_64</classifier>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>io.netty</groupId>
|
||||
<artifactId>netty-transport-native-epoll</artifactId>
|
||||
<version>${netty.version}</version>
|
||||
<scope>compile</scope>
|
||||
<classifier>linux-aarch_64</classifier>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>io.netty</groupId>
|
||||
<artifactId>netty-transport-native-kqueue</artifactId>
|
||||
<version>${netty.version}</version>
|
||||
<scope>compile</scope>
|
||||
<classifier>osx-x86_64</classifier>
|
||||
</dependency>
|
||||
<!-- Adventure text serialization -->
|
||||
<dependency>
|
||||
<groupId>net.kyori</groupId>
|
||||
<artifactId>adventure-text-serializer-legacy</artifactId>
|
||||
<version>${adventure.version}</version>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>net.kyori</groupId>
|
||||
<artifactId>adventure-text-serializer-plain</artifactId>
|
||||
<version>${adventure.version}</version>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
<!-- Other -->
|
||||
<dependency>
|
||||
<groupId>junit</groupId>
|
||||
<artifactId>junit</artifactId>
|
||||
<version>4.13.1</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-jar-plugin</artifactId>
|
||||
<version>3.2.0</version>
|
||||
<configuration>
|
||||
<excludes>
|
||||
<exclude>**/services/javax.annotation.processing.Processor</exclude>
|
||||
</excludes>
|
||||
</configuration>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>pl.project13.maven</groupId>
|
||||
<artifactId>git-commit-id-plugin</artifactId>
|
||||
<version>4.0.0</version>
|
||||
<executions>
|
||||
<execution>
|
||||
<id>get-the-git-infos</id>
|
||||
<goals>
|
||||
<goal>revision</goal>
|
||||
</goals>
|
||||
</execution>
|
||||
</executions>
|
||||
<configuration>
|
||||
<generateGitPropertiesFile>true</generateGitPropertiesFile>
|
||||
<generateGitPropertiesFilename>${project.build.outputDirectory}/git.properties</generateGitPropertiesFilename>
|
||||
<format>properties</format>
|
||||
<failOnNoGitDirectory>false</failOnNoGitDirectory>
|
||||
<failOnUnableToExtractRepoInfo>false</failOnUnableToExtractRepoInfo>
|
||||
<runOnlyOnce>false</runOnlyOnce>
|
||||
<verbose>true</verbose>
|
||||
<skipPoms>false</skipPoms>
|
||||
<excludeProperties>
|
||||
<excludeProperty>git.user.*</excludeProperty>
|
||||
<excludeProperty>git.*.user.*</excludeProperty>
|
||||
<excludeProperty>git.closest.*</excludeProperty>
|
||||
<excludeProperty>git.commit.id.describe</excludeProperty>
|
||||
<excludeProperty>git.commit.id.describe-short</excludeProperty>
|
||||
<excludeProperty>git.commit.message.short</excludeProperty>
|
||||
</excludeProperties>
|
||||
<commitIdGenerationMode>flat</commitIdGenerationMode>
|
||||
<gitDescribe>
|
||||
<always>true</always>
|
||||
</gitDescribe>
|
||||
</configuration>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>com.google.code.maven-replacer-plugin</groupId>
|
||||
<artifactId>replacer</artifactId>
|
||||
<version>1.5.3</version>
|
||||
<executions>
|
||||
<execution>
|
||||
<id>add-version</id>
|
||||
<phase>process-sources</phase>
|
||||
<goals>
|
||||
<goal>replace</goal>
|
||||
</goals>
|
||||
<configuration>
|
||||
<includes>
|
||||
<include>${project.basedir}/src/main/java/org/geysermc/connector/GeyserConnector.java</include>
|
||||
</includes>
|
||||
<replacements>
|
||||
<replacement>
|
||||
<token>String VERSION = ".*"</token>
|
||||
<value>String VERSION = "${project.version} (" + GIT_VERSION + ")"</value>
|
||||
</replacement>
|
||||
<replacement>
|
||||
<token>String GIT_VERSION = ".*"</token>
|
||||
<!--suppress UnresolvedMavenProperty -->
|
||||
<value>String GIT_VERSION = "git-${git.branch}-${git.commit.id.abbrev}"</value>
|
||||
</replacement>
|
||||
</replacements>
|
||||
</configuration>
|
||||
</execution>
|
||||
|
||||
<execution>
|
||||
<id>remove-version</id>
|
||||
<phase>process-classes</phase>
|
||||
<goals>
|
||||
<goal>replace</goal>
|
||||
</goals>
|
||||
<configuration>
|
||||
<includes>
|
||||
<include>${project.basedir}/src/main/java/org/geysermc/connector/GeyserConnector.java</include>
|
||||
</includes>
|
||||
<replacements>
|
||||
<replacement>
|
||||
<token>String VERSION = ".*"</token>
|
||||
<value>String VERSION = "DEV"</value>
|
||||
</replacement>
|
||||
<replacement>
|
||||
<token>String GIT_VERSION = ".*"</token>
|
||||
<value>String GIT_VERSION = "DEV"</value>
|
||||
</replacement>
|
||||
</replacements>
|
||||
</configuration>
|
||||
</execution>
|
||||
</executions>
|
||||
</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>
|
||||
|
|
@ -0,0 +1,67 @@
|
|||
/*
|
||||
* Copyright (c) 2019-2021 GeyserMC. http://geysermc.org
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*
|
||||
* @author GeyserMC
|
||||
* @link https://github.com/GeyserMC/Geyser
|
||||
*/
|
||||
|
||||
package org.geysermc.connector;
|
||||
|
||||
import org.geysermc.connector.common.AuthType;
|
||||
import org.geysermc.connector.configuration.GeyserJacksonConfiguration;
|
||||
import org.geysermc.connector.utils.LanguageUtils;
|
||||
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
|
||||
public class FloodgateKeyLoader {
|
||||
public static Path getKeyPath(GeyserJacksonConfiguration config, Path floodgateDataFolder, Path geyserDataFolder, GeyserLogger logger) {
|
||||
if (config.getRemote().getAuthType() != AuthType.FLOODGATE) {
|
||||
return geyserDataFolder.resolve(config.getFloodgateKeyFile());
|
||||
}
|
||||
|
||||
// Always prioritize Floodgate's key, if it is installed.
|
||||
// This mostly prevents people from trying to copy the key and corrupting it in the process
|
||||
if (floodgateDataFolder != null) {
|
||||
Path autoKey = floodgateDataFolder.resolve("key.pem");
|
||||
if (Files.exists(autoKey)) {
|
||||
logger.info(LanguageUtils.getLocaleStringLog("geyser.bootstrap.floodgate.auto_loaded"));
|
||||
return autoKey;
|
||||
} else {
|
||||
logger.error(LanguageUtils.getLocaleStringLog("geyser.bootstrap.floodgate.missing_key"));
|
||||
}
|
||||
}
|
||||
|
||||
Path floodgateKey;
|
||||
if (config.getFloodgateKeyFile().equals("public-key.pem")) {
|
||||
logger.info("Floodgate 2.0 doesn't use a public/private key system anymore. We'll search for key.pem instead");
|
||||
floodgateKey = geyserDataFolder.resolve("key.pem");
|
||||
} else {
|
||||
floodgateKey = geyserDataFolder.resolve(config.getFloodgateKeyFile());
|
||||
}
|
||||
|
||||
if (!Files.exists(floodgateKey)) {
|
||||
logger.error(LanguageUtils.getLocaleStringLog("geyser.bootstrap.floodgate.not_installed"));
|
||||
}
|
||||
|
||||
return floodgateKey;
|
||||
}
|
||||
}
|
||||
511
core/src/main/java/org/geysermc/connector/GeyserConnector.java
Normal file
511
core/src/main/java/org/geysermc/connector/GeyserConnector.java
Normal file
|
|
@ -0,0 +1,511 @@
|
|||
/*
|
||||
* Copyright (c) 2019-2021 GeyserMC. http://geysermc.org
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*
|
||||
* @author GeyserMC
|
||||
* @link https://github.com/GeyserMC/Geyser
|
||||
*/
|
||||
|
||||
package org.geysermc.connector;
|
||||
|
||||
import com.fasterxml.jackson.core.JsonParser;
|
||||
import com.fasterxml.jackson.databind.DeserializationFeature;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import com.github.steveice10.packetlib.tcp.TcpSession;
|
||||
import com.nukkitx.network.raknet.RakNetConstants;
|
||||
import com.nukkitx.network.util.EventLoops;
|
||||
import com.nukkitx.protocol.bedrock.BedrockServer;
|
||||
import io.netty.channel.epoll.Epoll;
|
||||
import io.netty.channel.kqueue.KQueue;
|
||||
import io.netty.util.NettyRuntime;
|
||||
import io.netty.util.concurrent.DefaultThreadFactory;
|
||||
import io.netty.util.internal.SystemPropertyUtil;
|
||||
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.configuration.GeyserConfiguration;
|
||||
import org.geysermc.connector.entity.EntityDefinitions;
|
||||
import org.geysermc.connector.metrics.Metrics;
|
||||
import org.geysermc.connector.network.ConnectorServerEventHandler;
|
||||
import org.geysermc.connector.network.session.GeyserSession;
|
||||
import org.geysermc.connector.network.translators.PacketTranslatorRegistry;
|
||||
import org.geysermc.connector.network.translators.chat.MessageTranslator;
|
||||
import org.geysermc.connector.network.translators.item.ItemTranslator;
|
||||
import org.geysermc.connector.network.translators.world.WorldManager;
|
||||
import org.geysermc.connector.registry.BlockRegistries;
|
||||
import org.geysermc.connector.registry.Registries;
|
||||
import org.geysermc.connector.scoreboard.ScoreboardUpdater;
|
||||
import org.geysermc.connector.skin.FloodgateSkinUploader;
|
||||
import org.geysermc.connector.utils.*;
|
||||
import org.geysermc.floodgate.crypto.AesCipher;
|
||||
import org.geysermc.floodgate.crypto.AesKeyProducer;
|
||||
import org.geysermc.floodgate.crypto.Base64Topping;
|
||||
import org.geysermc.floodgate.crypto.FloodgateCipher;
|
||||
import org.geysermc.floodgate.news.NewsItemAction;
|
||||
import org.geysermc.floodgate.time.TimeSyncer;
|
||||
import org.jetbrains.annotations.Contract;
|
||||
|
||||
import javax.naming.directory.Attribute;
|
||||
import javax.naming.directory.InitialDirContext;
|
||||
import java.net.InetAddress;
|
||||
import java.net.InetSocketAddress;
|
||||
import java.net.UnknownHostException;
|
||||
import java.security.Key;
|
||||
import java.text.DecimalFormat;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Properties;
|
||||
import java.util.UUID;
|
||||
import java.util.concurrent.Executors;
|
||||
import java.util.concurrent.ScheduledExecutorService;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
@Getter
|
||||
public class GeyserConnector {
|
||||
public static final ObjectMapper JSON_MAPPER = new ObjectMapper()
|
||||
.enable(JsonParser.Feature.IGNORE_UNDEFINED)
|
||||
.enable(JsonParser.Feature.ALLOW_COMMENTS)
|
||||
.disable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES)
|
||||
.enable(JsonParser.Feature.ALLOW_UNQUOTED_FIELD_NAMES)
|
||||
.enable(JsonParser.Feature.ALLOW_SINGLE_QUOTES);
|
||||
|
||||
public static final String NAME = "Geyser";
|
||||
public static final String GIT_VERSION = "DEV"; // A fallback for running in IDEs
|
||||
public static final String VERSION = "DEV"; // A fallback for running in IDEs
|
||||
|
||||
/**
|
||||
* Oauth client ID for Microsoft authentication
|
||||
*/
|
||||
public static final String OAUTH_CLIENT_ID = "204cefd1-4818-4de1-b98d-513fae875d88";
|
||||
|
||||
private static final String IP_REGEX = "\\b\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}\\b";
|
||||
|
||||
private final SessionManager sessionManager = new SessionManager();
|
||||
|
||||
private static GeyserConnector instance;
|
||||
|
||||
/**
|
||||
* This is used in GeyserConnect to stop the bedrock server binding to a port
|
||||
*/
|
||||
@Setter
|
||||
private static boolean shouldStartListener = true;
|
||||
|
||||
private final TimeSyncer timeSyncer;
|
||||
private FloodgateCipher cipher;
|
||||
private FloodgateSkinUploader skinUploader;
|
||||
private final NewsHandler newsHandler;
|
||||
|
||||
private volatile boolean shuttingDown = false;
|
||||
|
||||
private final ScheduledExecutorService scheduledThread;
|
||||
|
||||
private final BedrockServer bedrockServer;
|
||||
private final PlatformType platformType;
|
||||
private final GeyserBootstrap bootstrap;
|
||||
|
||||
private final Metrics metrics;
|
||||
|
||||
private GeyserConnector(PlatformType platformType, GeyserBootstrap bootstrap) {
|
||||
long startupTime = System.currentTimeMillis();
|
||||
|
||||
instance = this;
|
||||
|
||||
this.bootstrap = bootstrap;
|
||||
|
||||
GeyserLogger logger = bootstrap.getGeyserLogger();
|
||||
GeyserConfiguration config = bootstrap.getGeyserConfig();
|
||||
|
||||
this.platformType = platformType;
|
||||
|
||||
logger.info("******************************************");
|
||||
logger.info("");
|
||||
logger.info(LanguageUtils.getLocaleStringLog("geyser.core.load", NAME, VERSION));
|
||||
logger.info("");
|
||||
logger.info("******************************************");
|
||||
|
||||
this.scheduledThread = Executors.newSingleThreadScheduledExecutor(new DefaultThreadFactory("Geyser Scheduled Thread"));
|
||||
|
||||
logger.setDebug(config.isDebugMode());
|
||||
|
||||
PacketTranslatorRegistry.init();
|
||||
|
||||
/* Initialize translators and registries */
|
||||
BlockRegistries.init();
|
||||
Registries.init();
|
||||
|
||||
EntityDefinitions.init();
|
||||
ItemTranslator.init();
|
||||
MessageTranslator.init();
|
||||
LocaleUtils.init();
|
||||
ScoreboardUpdater.init();
|
||||
|
||||
ResourcePack.loadPacks();
|
||||
|
||||
if (platformType != PlatformType.STANDALONE && config.getRemote().getAddress().equals("auto")) {
|
||||
// Set the remote address to localhost since that is where we are always connecting
|
||||
try {
|
||||
config.getRemote().setAddress(InetAddress.getLocalHost().getHostAddress());
|
||||
} catch (UnknownHostException ex) {
|
||||
logger.debug("Unknown host when trying to find localhost.");
|
||||
if (config.isDebugMode()) {
|
||||
ex.printStackTrace();
|
||||
}
|
||||
config.getRemote().setAddress(InetAddress.getLoopbackAddress().getHostAddress());
|
||||
}
|
||||
}
|
||||
String remoteAddress = config.getRemote().getAddress();
|
||||
// Filters whether it is not an IP address or localhost, because otherwise it is not possible to find out an SRV entry.
|
||||
if (!remoteAddress.matches(IP_REGEX) && !remoteAddress.equalsIgnoreCase("localhost")) {
|
||||
int remotePort;
|
||||
try {
|
||||
// Searches for a server address and a port from a SRV record of the specified host name
|
||||
InitialDirContext ctx = new InitialDirContext();
|
||||
Attribute attr = ctx.getAttributes("dns:///_minecraft._tcp." + remoteAddress, new String[]{"SRV"}).get("SRV");
|
||||
// size > 0 = SRV entry found
|
||||
if (attr != null && attr.size() > 0) {
|
||||
String[] record = ((String) attr.get(0)).split(" ");
|
||||
// Overwrites the existing address and port with that from the SRV record.
|
||||
config.getRemote().setAddress(remoteAddress = record[3]);
|
||||
config.getRemote().setPort(remotePort = Integer.parseInt(record[2]));
|
||||
logger.debug("Found SRV record \"" + remoteAddress + ":" + remotePort + "\"");
|
||||
}
|
||||
} catch (Exception | NoClassDefFoundError ex) { // Check for a NoClassDefFoundError to prevent Android crashes
|
||||
logger.debug("Exception while trying to find an SRV record for the remote host.");
|
||||
if (config.isDebugMode())
|
||||
ex.printStackTrace(); // Otherwise we can get a stack trace for any domain that doesn't have an SRV record
|
||||
}
|
||||
}
|
||||
|
||||
// Ensure that PacketLib does not create an event loop for handling packets; we'll do that ourselves
|
||||
TcpSession.USE_EVENT_LOOP_FOR_PACKETS = false;
|
||||
|
||||
TimeSyncer timeSyncer = null;
|
||||
if (config.getRemote().getAuthType() == AuthType.FLOODGATE) {
|
||||
timeSyncer = new TimeSyncer(Constants.NTP_SERVER);
|
||||
try {
|
||||
Key key = new AesKeyProducer().produceFrom(config.getFloodgateKeyPath());
|
||||
cipher = new AesCipher(new Base64Topping());
|
||||
cipher.init(key);
|
||||
logger.info(LanguageUtils.getLocaleStringLog("geyser.auth.floodgate.loaded_key"));
|
||||
skinUploader = new FloodgateSkinUploader(this).start();
|
||||
} catch (Exception exception) {
|
||||
logger.severe(LanguageUtils.getLocaleStringLog("geyser.auth.floodgate.bad_key"), exception);
|
||||
}
|
||||
}
|
||||
this.timeSyncer = timeSyncer;
|
||||
|
||||
String branch = "unknown";
|
||||
int buildNumber = -1;
|
||||
if (this.isProductionEnvironment()) {
|
||||
try {
|
||||
Properties gitProperties = new Properties();
|
||||
gitProperties.load(FileUtils.getResource("git.properties"));
|
||||
branch = gitProperties.getProperty("git.branch");
|
||||
String build = gitProperties.getProperty("git.build.number");
|
||||
if (build != null) {
|
||||
buildNumber = Integer.parseInt(build);
|
||||
}
|
||||
} catch (Throwable e) {
|
||||
logger.error("Failed to read git.properties", e);
|
||||
}
|
||||
} else {
|
||||
logger.debug("Not getting git properties for the news handler as we are in a development environment.");
|
||||
}
|
||||
newsHandler = new NewsHandler(branch, buildNumber);
|
||||
|
||||
CooldownUtils.setDefaultShowCooldown(config.getShowCooldown());
|
||||
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();
|
||||
logger.debug("Setting MTU to " + config.getMtu());
|
||||
|
||||
Integer bedrockThreadCount = Integer.getInteger("Geyser.BedrockNetworkThreads");
|
||||
if (bedrockThreadCount == null) {
|
||||
// Copy the code from Netty's default thread count fallback
|
||||
bedrockThreadCount = Math.max(1, SystemPropertyUtil.getInt("io.netty.eventLoopThreads", NettyRuntime.availableProcessors() * 2));
|
||||
}
|
||||
|
||||
boolean enableProxyProtocol = config.getBedrock().isEnableProxyProtocol();
|
||||
bedrockServer = new BedrockServer(
|
||||
new InetSocketAddress(config.getBedrock().getAddress(), config.getBedrock().getPort()),
|
||||
bedrockThreadCount,
|
||||
EventLoops.commonGroup(),
|
||||
enableProxyProtocol
|
||||
);
|
||||
|
||||
if (config.isDebugMode()) {
|
||||
logger.debug("EventLoop type: " + EventLoops.getChannelType());
|
||||
if (EventLoops.getChannelType() == EventLoops.ChannelType.NIO) {
|
||||
if (System.getProperties().contains("disableNativeEventLoop")) {
|
||||
logger.debug("EventLoop type is NIO because native event loops are disabled.");
|
||||
} else {
|
||||
logger.debug("Reason for no Epoll: " + Epoll.unavailabilityCause().toString());
|
||||
logger.debug("Reason for no KQueue: " + KQueue.unavailabilityCause().toString());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bedrockServer.setHandler(new ConnectorServerEventHandler(this));
|
||||
|
||||
if (shouldStartListener) {
|
||||
bedrockServer.bind().whenComplete((avoid, throwable) -> {
|
||||
if (throwable == null) {
|
||||
logger.info(LanguageUtils.getLocaleStringLog("geyser.core.start", config.getBedrock().getAddress(), String.valueOf(config.getBedrock().getPort())));
|
||||
} else {
|
||||
logger.severe(LanguageUtils.getLocaleStringLog("geyser.core.fail", config.getBedrock().getAddress(), String.valueOf(config.getBedrock().getPort())));
|
||||
throwable.printStackTrace();
|
||||
}
|
||||
}).join();
|
||||
}
|
||||
|
||||
if (config.getMetrics().isEnabled()) {
|
||||
metrics = new Metrics(this, "GeyserMC", config.getMetrics().getUniqueId(), false, java.util.logging.Logger.getLogger(""));
|
||||
metrics.addCustomChart(new Metrics.SingleLineChart("players", sessionManager::size));
|
||||
// Prevent unwanted words best we can
|
||||
metrics.addCustomChart(new Metrics.SimplePie("authMode", () -> config.getRemote().getAuthType().toString().toLowerCase()));
|
||||
metrics.addCustomChart(new Metrics.SimplePie("platform", platformType::getPlatformName));
|
||||
metrics.addCustomChart(new Metrics.SimplePie("defaultLocale", LanguageUtils::getDefaultLocale));
|
||||
metrics.addCustomChart(new Metrics.SimplePie("version", () -> GeyserConnector.VERSION));
|
||||
metrics.addCustomChart(new Metrics.AdvancedPie("playerPlatform", () -> {
|
||||
Map<String, Integer> valueMap = new HashMap<>();
|
||||
for (GeyserSession session : sessionManager.getAllSessions()) {
|
||||
if (session == null) continue;
|
||||
if (session.getClientData() == null) continue;
|
||||
String os = session.getClientData().getDeviceOs().toString();
|
||||
if (!valueMap.containsKey(os)) {
|
||||
valueMap.put(os, 1);
|
||||
} else {
|
||||
valueMap.put(os, valueMap.get(os) + 1);
|
||||
}
|
||||
}
|
||||
return valueMap;
|
||||
}));
|
||||
metrics.addCustomChart(new Metrics.AdvancedPie("playerVersion", () -> {
|
||||
Map<String, Integer> valueMap = new HashMap<>();
|
||||
for (GeyserSession session : sessionManager.getAllSessions()) {
|
||||
if (session == null) continue;
|
||||
if (session.getClientData() == null) continue;
|
||||
String version = session.getClientData().getGameVersion();
|
||||
if (!valueMap.containsKey(version)) {
|
||||
valueMap.put(version, 1);
|
||||
} else {
|
||||
valueMap.put(version, valueMap.get(version) + 1);
|
||||
}
|
||||
}
|
||||
return valueMap;
|
||||
}));
|
||||
|
||||
String minecraftVersion = bootstrap.getMinecraftServerVersion();
|
||||
if (minecraftVersion != null) {
|
||||
Map<String, Map<String, Integer>> versionMap = new HashMap<>();
|
||||
Map<String, Integer> platformMap = new HashMap<>();
|
||||
platformMap.put(platformType.getPlatformName(), 1);
|
||||
versionMap.put(minecraftVersion, platformMap);
|
||||
|
||||
metrics.addCustomChart(new Metrics.DrilldownPie("minecraftServerVersion", () -> {
|
||||
// By the end, we should return, for example:
|
||||
// 1.16.5 => (Spigot, 1)
|
||||
return versionMap;
|
||||
}));
|
||||
}
|
||||
|
||||
// The following code can be attributed to the PaperMC project
|
||||
// https://github.com/PaperMC/Paper/blob/master/Spigot-Server-Patches/0005-Paper-Metrics.patch#L614
|
||||
metrics.addCustomChart(new Metrics.DrilldownPie("javaVersion", () -> {
|
||||
Map<String, Map<String, Integer>> map = new HashMap<>();
|
||||
String javaVersion = System.getProperty("java.version");
|
||||
Map<String, Integer> entry = new HashMap<>();
|
||||
entry.put(javaVersion, 1);
|
||||
|
||||
// http://openjdk.java.net/jeps/223
|
||||
// Java decided to change their versioning scheme and in doing so modified the
|
||||
// java.version system property to return $major[.$minor][.$security][-ea], as opposed to
|
||||
// 1.$major.0_$identifier we can handle pre-9 by checking if the "major" is equal to "1",
|
||||
// otherwise, 9+
|
||||
String majorVersion = javaVersion.split("\\.")[0];
|
||||
String release;
|
||||
|
||||
int indexOf = javaVersion.lastIndexOf('.');
|
||||
|
||||
if (majorVersion.equals("1")) {
|
||||
release = "Java " + javaVersion.substring(0, indexOf);
|
||||
} else {
|
||||
// of course, it really wouldn't be all that simple if they didn't add a quirk, now
|
||||
// would it valid strings for the major may potentially include values such as -ea to
|
||||
// denote a pre release
|
||||
Matcher versionMatcher = Pattern.compile("\\d+").matcher(majorVersion);
|
||||
if (versionMatcher.find()) {
|
||||
majorVersion = versionMatcher.group(0);
|
||||
}
|
||||
release = "Java " + majorVersion;
|
||||
}
|
||||
map.put(release, entry);
|
||||
return map;
|
||||
}));
|
||||
} else {
|
||||
metrics = null;
|
||||
}
|
||||
|
||||
boolean isGui = false;
|
||||
// This will check if we are in standalone and get the 'useGui' variable from there
|
||||
if (platformType == PlatformType.STANDALONE) {
|
||||
try {
|
||||
Class<?> cls = Class.forName("org.geysermc.platform.standalone.GeyserStandaloneBootstrap");
|
||||
isGui = (boolean) cls.getMethod("isUseGui").invoke(cls.cast(bootstrap));
|
||||
} catch (Exception e) {
|
||||
logger.debug("Failed detecting if standalone is using a GUI; if this is a GeyserConnect instance this can be safely ignored.");
|
||||
}
|
||||
}
|
||||
|
||||
double completeTime = (System.currentTimeMillis() - startupTime) / 1000D;
|
||||
String message = LanguageUtils.getLocaleStringLog("geyser.core.finish.done", new DecimalFormat("#.###").format(completeTime)) + " ";
|
||||
if (isGui) {
|
||||
message += LanguageUtils.getLocaleStringLog("geyser.core.finish.gui");
|
||||
} else {
|
||||
message += LanguageUtils.getLocaleStringLog("geyser.core.finish.console");
|
||||
}
|
||||
logger.info(message);
|
||||
|
||||
if (platformType == PlatformType.STANDALONE) {
|
||||
logger.warning(LanguageUtils.getLocaleStringLog("geyser.core.movement_warn"));
|
||||
}
|
||||
|
||||
newsHandler.handleNews(null, NewsItemAction.ON_SERVER_STARTED);
|
||||
}
|
||||
|
||||
public void shutdown() {
|
||||
bootstrap.getGeyserLogger().info(LanguageUtils.getLocaleStringLog("geyser.core.shutdown"));
|
||||
shuttingDown = true;
|
||||
|
||||
if (sessionManager.size() >= 1) {
|
||||
bootstrap.getGeyserLogger().info(LanguageUtils.getLocaleStringLog("geyser.core.shutdown.kick.log", sessionManager.size()));
|
||||
sessionManager.disconnectAll("geyser.core.shutdown.kick.message");
|
||||
bootstrap.getGeyserLogger().info(LanguageUtils.getLocaleStringLog("geyser.core.shutdown.kick.done"));
|
||||
}
|
||||
|
||||
scheduledThread.shutdown();
|
||||
bedrockServer.close();
|
||||
if (timeSyncer != null) {
|
||||
timeSyncer.shutdown();
|
||||
}
|
||||
if (skinUploader != null) {
|
||||
skinUploader.close();
|
||||
}
|
||||
newsHandler.shutdown();
|
||||
this.getCommandManager().getCommands().clear();
|
||||
|
||||
bootstrap.getGeyserLogger().info(LanguageUtils.getLocaleStringLog("geyser.core.shutdown.done"));
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a player by their current UUID
|
||||
*
|
||||
* @param uuid the uuid
|
||||
* @return the player or <code>null</code> if there is no player online with this UUID
|
||||
*/
|
||||
@Contract("null -> null")
|
||||
public GeyserSession getPlayerByUuid(UUID uuid) {
|
||||
if (uuid == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return sessionManager.getSessions().get(uuid);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a player by their Xbox user identifier
|
||||
*
|
||||
* @param xuid the Xbox user identifier
|
||||
* @return the player or <code>null</code> if there is no player online with this xuid
|
||||
*/
|
||||
@SuppressWarnings("unused") // API usage
|
||||
public GeyserSession getPlayerByXuid(String xuid) {
|
||||
for (GeyserSession session : sessionManager.getPendingSessions()) {
|
||||
if (session.getAuthData().getXboxUUID().equals(xuid)) {
|
||||
return session;
|
||||
}
|
||||
}
|
||||
for (GeyserSession session : sessionManager.getSessions().values()) {
|
||||
if (session.getAuthData().getXboxUUID().equals(xuid)) {
|
||||
return session;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public static GeyserConnector start(PlatformType platformType, GeyserBootstrap bootstrap) {
|
||||
return new GeyserConnector(platformType, bootstrap);
|
||||
}
|
||||
|
||||
public void reload() {
|
||||
shutdown();
|
||||
bootstrap.onEnable();
|
||||
}
|
||||
|
||||
public GeyserLogger getLogger() {
|
||||
return bootstrap.getGeyserLogger();
|
||||
}
|
||||
|
||||
public GeyserConfiguration getConfig() {
|
||||
return bootstrap.getGeyserConfig();
|
||||
}
|
||||
|
||||
public CommandManager getCommandManager() {
|
||||
return bootstrap.getGeyserCommandManager();
|
||||
}
|
||||
|
||||
public WorldManager getWorldManager() {
|
||||
return bootstrap.getWorldManager();
|
||||
}
|
||||
|
||||
public TimeSyncer getTimeSyncer() {
|
||||
return timeSyncer;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns false if this Geyser instance is running in an IDE. This only needs to be used in cases where files
|
||||
* expected to be in a jarfile are not present.
|
||||
*
|
||||
* @return true if the version number is not 'DEV'.
|
||||
*/
|
||||
public boolean isProductionEnvironment() {
|
||||
//noinspection ConstantConditions - changes in production
|
||||
return !"DEV".equals(GeyserConnector.VERSION);
|
||||
}
|
||||
|
||||
/**
|
||||
* Deprecated. Get the AuthType from the GeyserConfiguration through {@link GeyserConnector#getConfig()}
|
||||
* @return The
|
||||
*/
|
||||
@Deprecated
|
||||
public AuthType getDefaultAuthType() {
|
||||
return getConfig().getRemote().getAuthType();
|
||||
}
|
||||
|
||||
public static GeyserConnector getInstance() {
|
||||
return instance;
|
||||
}
|
||||
}
|
||||
92
core/src/main/java/org/geysermc/connector/GeyserLogger.java
Normal file
92
core/src/main/java/org/geysermc/connector/GeyserLogger.java
Normal file
|
|
@ -0,0 +1,92 @@
|
|||
/*
|
||||
* Copyright (c) 2019-2021 GeyserMC. http://geysermc.org
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*
|
||||
* @author GeyserMC
|
||||
* @link https://github.com/GeyserMC/Geyser
|
||||
*/
|
||||
|
||||
package org.geysermc.connector;
|
||||
|
||||
public interface GeyserLogger {
|
||||
|
||||
/**
|
||||
* Logs a severe message to console
|
||||
*
|
||||
* @param message the message to log
|
||||
*/
|
||||
void severe(String message);
|
||||
|
||||
/**
|
||||
* Logs a severe message and an exception to console
|
||||
*
|
||||
* @param message the message to log
|
||||
* @param error the error to throw
|
||||
*/
|
||||
void severe(String message, Throwable error);
|
||||
|
||||
/**
|
||||
* Logs an error message to console
|
||||
*
|
||||
* @param message the message to log
|
||||
*/
|
||||
void error(String message);
|
||||
|
||||
/**
|
||||
* Logs an error message and an exception to console
|
||||
*
|
||||
* @param message the message to log
|
||||
* @param error the error to throw
|
||||
*/
|
||||
void error(String message, Throwable error);
|
||||
|
||||
/**
|
||||
* Logs a warning message to console
|
||||
*
|
||||
* @param message the message to log
|
||||
*/
|
||||
void warning(String message);
|
||||
|
||||
/**
|
||||
* Logs an info message to console
|
||||
*
|
||||
* @param message the message to log
|
||||
*/
|
||||
void info(String message);
|
||||
|
||||
/**
|
||||
* Logs a debug message to console
|
||||
*
|
||||
* @param message the message to log
|
||||
*/
|
||||
void debug(String message);
|
||||
|
||||
/**
|
||||
* Sets if the logger should print debug messages
|
||||
*
|
||||
* @param debug if the logger should print debug messages
|
||||
*/
|
||||
void setDebug(boolean debug);
|
||||
|
||||
/**
|
||||
* If debug is enabled for this logger
|
||||
*/
|
||||
boolean isDebug();
|
||||
}
|
||||
|
|
@ -0,0 +1,94 @@
|
|||
/*
|
||||
* Copyright (c) 2019-2021 GeyserMC. http://geysermc.org
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*
|
||||
* @author GeyserMC
|
||||
* @link https://github.com/GeyserMC/Geyser
|
||||
*/
|
||||
|
||||
package org.geysermc.connector;
|
||||
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import lombok.AccessLevel;
|
||||
import lombok.Getter;
|
||||
import org.geysermc.connector.network.session.GeyserSession;
|
||||
import org.geysermc.connector.utils.LanguageUtils;
|
||||
|
||||
import java.util.*;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
public final class SessionManager {
|
||||
/**
|
||||
* A list of all players who don't currently have a permanent UUID attached yet.
|
||||
*/
|
||||
@Getter(AccessLevel.PACKAGE)
|
||||
private final Set<GeyserSession> pendingSessions = ConcurrentHashMap.newKeySet();
|
||||
/**
|
||||
* A list of all players who are currently in-game.
|
||||
*/
|
||||
@Getter
|
||||
private final Map<UUID, GeyserSession> sessions = new ConcurrentHashMap<>();
|
||||
|
||||
/**
|
||||
* Called once the player has successfully authenticated to the Geyser server.
|
||||
*/
|
||||
public void addPendingSession(GeyserSession session) {
|
||||
pendingSessions.add(session);
|
||||
}
|
||||
|
||||
/**
|
||||
* Called once a player has successfully logged into their Java server.
|
||||
*/
|
||||
public void addSession(UUID uuid, GeyserSession session) {
|
||||
pendingSessions.remove(session);
|
||||
sessions.put(uuid, session);
|
||||
}
|
||||
|
||||
public void removeSession(GeyserSession session) {
|
||||
if (sessions.remove(session.getPlayerEntity().getUuid()) == null) {
|
||||
// Session was likely pending
|
||||
pendingSessions.remove(session);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new, immutable list containing all pending and active sessions.
|
||||
*/
|
||||
public Collection<GeyserSession> getAllSessions() {
|
||||
return ImmutableList.<GeyserSession>builder() // builderWithExpectedSize is probably not a good idea yet as older Spigot builds probably won't have it.
|
||||
.addAll(pendingSessions)
|
||||
.addAll(sessions.values())
|
||||
.build();
|
||||
}
|
||||
|
||||
public void disconnectAll(String message) {
|
||||
Collection<GeyserSession> sessions = getAllSessions();
|
||||
for (GeyserSession session : sessions) {
|
||||
session.disconnect(LanguageUtils.getPlayerLocaleString(message, session.getLocale()));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the total amount of sessions, including those pending.
|
||||
*/
|
||||
public int size() {
|
||||
return pendingSessions.size() + sessions.size();
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,128 @@
|
|||
/*
|
||||
* Copyright (c) 2019-2021 GeyserMC. http://geysermc.org
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*
|
||||
* @author GeyserMC
|
||||
* @link https://github.com/GeyserMC/Geyser
|
||||
*/
|
||||
|
||||
package org.geysermc.connector.bootstrap;
|
||||
|
||||
import org.geysermc.connector.GeyserLogger;
|
||||
import org.geysermc.connector.command.CommandManager;
|
||||
import org.geysermc.connector.configuration.GeyserConfiguration;
|
||||
import org.geysermc.connector.dump.BootstrapDumpInfo;
|
||||
import org.geysermc.connector.network.translators.world.GeyserWorldManager;
|
||||
import org.geysermc.connector.network.translators.world.WorldManager;
|
||||
import org.geysermc.connector.ping.IGeyserPingPassthrough;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
import java.net.SocketAddress;
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.Paths;
|
||||
|
||||
public interface GeyserBootstrap {
|
||||
|
||||
GeyserWorldManager DEFAULT_CHUNK_MANAGER = new GeyserWorldManager();
|
||||
|
||||
/**
|
||||
* Called when the GeyserBootstrap is enabled
|
||||
*/
|
||||
void onEnable();
|
||||
|
||||
/**
|
||||
* Called when the GeyserBootstrap is disabled
|
||||
*/
|
||||
void onDisable();
|
||||
|
||||
/**
|
||||
* Returns the current GeyserConfiguration
|
||||
*
|
||||
* @return The current GeyserConfiguration
|
||||
*/
|
||||
GeyserConfiguration getGeyserConfig();
|
||||
|
||||
/**
|
||||
* Returns the current GeyserLogger
|
||||
*
|
||||
* @return The current GeyserLogger
|
||||
*/
|
||||
GeyserLogger getGeyserLogger();
|
||||
|
||||
/**
|
||||
* Returns the current CommandManager
|
||||
*
|
||||
* @return The current CommandManager
|
||||
*/
|
||||
CommandManager getGeyserCommandManager();
|
||||
|
||||
/**
|
||||
* Returns the current PingPassthrough manager
|
||||
*
|
||||
* @return The current PingPassthrough manager
|
||||
*/
|
||||
IGeyserPingPassthrough getGeyserPingPassthrough();
|
||||
|
||||
/**
|
||||
* Returns the current WorldManager
|
||||
*
|
||||
* @return the current WorldManager
|
||||
*/
|
||||
default WorldManager getWorldManager() {
|
||||
return DEFAULT_CHUNK_MANAGER;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the data folder where files get stored
|
||||
*
|
||||
* @return Path location of data folder
|
||||
*/
|
||||
Path getConfigFolder();
|
||||
|
||||
/**
|
||||
* Information used for the bootstrap section of the debug dump
|
||||
*
|
||||
* @return The info about the bootstrap
|
||||
*/
|
||||
BootstrapDumpInfo getDumpInfo();
|
||||
|
||||
/**
|
||||
* Returns the Minecraft version currently being used on the server. This should be only be implemented on platforms
|
||||
* that have direct server access - platforms such as proxies always have to be on their latest version to support
|
||||
* the newest Minecraft version, but older servers can use ViaVersion to enable newer versions to join.
|
||||
* <br>
|
||||
* If used, this should not be null before {@link org.geysermc.connector.GeyserConnector} initialization.
|
||||
*
|
||||
* @return the Minecraft version being used on the server, or <code>null</code> if not applicable
|
||||
*/
|
||||
@Nullable
|
||||
default String getMinecraftServerVersion() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
default SocketAddress getSocketAddress() {
|
||||
return null;
|
||||
}
|
||||
|
||||
default Path getLogsPath() {
|
||||
return Paths.get("logs/latest.log");
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,98 @@
|
|||
/*
|
||||
* Copyright (c) 2019-2021 GeyserMC. http://geysermc.org
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*
|
||||
* @author GeyserMC
|
||||
* @link https://github.com/GeyserMC/Geyser
|
||||
*/
|
||||
|
||||
package org.geysermc.connector.command;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import org.geysermc.connector.GeyserConnector;
|
||||
import org.geysermc.connector.network.session.GeyserSession;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* Represents helper functions for listening to {@code /geyser} commands.
|
||||
*/
|
||||
@AllArgsConstructor
|
||||
public class CommandExecutor {
|
||||
|
||||
protected final GeyserConnector connector;
|
||||
|
||||
public GeyserCommand getCommand(String label) {
|
||||
return connector.getCommandManager().getCommands().get(label);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public GeyserSession getGeyserSession(CommandSender sender) {
|
||||
if (sender.isConsole()) {
|
||||
return null;
|
||||
}
|
||||
|
||||
for (GeyserSession session : connector.getSessionManager().getSessions().values()) {
|
||||
if (sender.getName().equals(session.getPlayerEntity().getUsername())) {
|
||||
return session;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine which subcommands to suggest in the tab complete for the main /geyser command by a given command sender.
|
||||
*
|
||||
* @param sender The command sender to receive the tab complete suggestions.
|
||||
* If the command sender is a bedrock player, an empty list will be returned as bedrock players do not get command argument suggestions.
|
||||
* If the command sender is not a bedrock player, bedrock commands will not be shown.
|
||||
* If the command sender does not have the permission for a given command, the command will not be shown.
|
||||
* @return A list of command names to include in the tab complete
|
||||
*/
|
||||
public List<String> tabComplete(CommandSender sender) {
|
||||
if (getGeyserSession(sender) != null) {
|
||||
// Bedrock doesn't get tab completions or argument suggestions
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
List<String> availableCommands = new ArrayList<>();
|
||||
Map<String, GeyserCommand> commands = connector.getCommandManager().getCommands();
|
||||
|
||||
// Only show commands they have permission to use
|
||||
for (String name : commands.keySet()) {
|
||||
GeyserCommand geyserCommand = commands.get(name);
|
||||
if (sender.hasPermission(geyserCommand.getPermission())) {
|
||||
|
||||
if (geyserCommand.isBedrockOnly()) {
|
||||
// Don't show commands the JE player can't run
|
||||
continue;
|
||||
}
|
||||
|
||||
availableCommands.add(name);
|
||||
}
|
||||
}
|
||||
|
||||
return availableCommands;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,121 @@
|
|||
/*
|
||||
* Copyright (c) 2019-2021 GeyserMC. http://geysermc.org
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*
|
||||
* @author GeyserMC
|
||||
* @link https://github.com/GeyserMC/Geyser
|
||||
*/
|
||||
|
||||
package org.geysermc.connector.command;
|
||||
|
||||
import lombok.Getter;
|
||||
|
||||
import org.geysermc.common.PlatformType;
|
||||
import org.geysermc.connector.GeyserConnector;
|
||||
import org.geysermc.connector.command.defaults.*;
|
||||
import org.geysermc.connector.network.session.GeyserSession;
|
||||
import org.geysermc.connector.utils.LanguageUtils;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
public abstract class CommandManager {
|
||||
|
||||
@Getter
|
||||
private final Map<String, GeyserCommand> commands = Collections.synchronizedMap(new HashMap<>());
|
||||
|
||||
private final GeyserConnector connector;
|
||||
|
||||
public CommandManager(GeyserConnector connector) {
|
||||
this.connector = connector;
|
||||
|
||||
registerCommand(new HelpCommand(connector, "help", "geyser.commands.help.desc", "geyser.command.help"));
|
||||
registerCommand(new ListCommand(connector, "list", "geyser.commands.list.desc", "geyser.command.list"));
|
||||
registerCommand(new ReloadCommand(connector, "reload", "geyser.commands.reload.desc", "geyser.command.reload"));
|
||||
registerCommand(new OffhandCommand(connector, "offhand", "geyser.commands.offhand.desc", "geyser.command.offhand"));
|
||||
registerCommand(new DumpCommand(connector, "dump", "geyser.commands.dump.desc", "geyser.command.dump"));
|
||||
registerCommand(new VersionCommand(connector, "version", "geyser.commands.version.desc", "geyser.command.version"));
|
||||
registerCommand(new SettingsCommand(connector, "settings", "geyser.commands.settings.desc", "geyser.command.settings"));
|
||||
registerCommand(new StatisticsCommand(connector, "statistics", "geyser.commands.statistics.desc", "geyser.command.statistics"));
|
||||
registerCommand(new AdvancementsCommand("advancements", "geyser.commands.advancements.desc", "geyser.command.advancements"));
|
||||
if (GeyserConnector.getInstance().getPlatformType() == PlatformType.STANDALONE) {
|
||||
registerCommand(new StopCommand(connector, "stop", "geyser.commands.stop.desc", "geyser.command.stop"));
|
||||
}
|
||||
}
|
||||
|
||||
public void registerCommand(GeyserCommand command) {
|
||||
commands.put(command.getName(), command);
|
||||
connector.getLogger().debug(LanguageUtils.getLocaleStringLog("geyser.commands.registered", command.getName()));
|
||||
|
||||
if (command.getAliases().isEmpty())
|
||||
return;
|
||||
|
||||
for (String alias : command.getAliases())
|
||||
commands.put(alias, command);
|
||||
}
|
||||
|
||||
public void runCommand(CommandSender sender, String command) {
|
||||
if (!command.startsWith("geyser "))
|
||||
return;
|
||||
|
||||
command = command.trim().replace("geyser ", "");
|
||||
String label;
|
||||
String[] args;
|
||||
|
||||
if (!command.contains(" ")) {
|
||||
label = command.toLowerCase();
|
||||
args = new String[0];
|
||||
} else {
|
||||
label = command.substring(0, command.indexOf(" ")).toLowerCase();
|
||||
String argLine = command.substring(command.indexOf(" ") + 1);
|
||||
args = argLine.contains(" ") ? argLine.split(" ") : new String[] { argLine };
|
||||
}
|
||||
|
||||
GeyserCommand cmd = commands.get(label);
|
||||
if (cmd == null) {
|
||||
connector.getLogger().error(LanguageUtils.getLocaleStringLog("geyser.commands.invalid"));
|
||||
return;
|
||||
}
|
||||
|
||||
if (sender instanceof GeyserSession) {
|
||||
cmd.execute((GeyserSession) sender, sender, args);
|
||||
} else {
|
||||
if (!cmd.isBedrockOnly()) {
|
||||
cmd.execute(null, sender, args);
|
||||
} else {
|
||||
connector.getLogger().error(LanguageUtils.getLocaleStringLog("geyser.bootstrap.command.bedrock_only"));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @return a list of all subcommands under {@code /geyser}.
|
||||
*/
|
||||
public List<String> getCommandNames() {
|
||||
return Arrays.asList(connector.getCommandManager().getCommands().keySet().toArray(new String[0]));
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the description of the given command
|
||||
*
|
||||
* @param command Command to get the description for
|
||||
* @return Command description
|
||||
*/
|
||||
public abstract String getDescription(String command);
|
||||
}
|
||||
|
|
@ -0,0 +1,67 @@
|
|||
/*
|
||||
* Copyright (c) 2019-2021 GeyserMC. http://geysermc.org
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*
|
||||
* @author GeyserMC
|
||||
* @link https://github.com/GeyserMC/Geyser
|
||||
*/
|
||||
|
||||
package org.geysermc.connector.command;
|
||||
|
||||
import org.geysermc.connector.utils.LanguageUtils;
|
||||
|
||||
/**
|
||||
* Implemented on top of any class that can send a command.
|
||||
* For example, it wraps around Spigot's CommandSender class.
|
||||
*/
|
||||
public interface CommandSender {
|
||||
|
||||
String getName();
|
||||
|
||||
default void sendMessage(String[] messages) {
|
||||
for (String message : messages) {
|
||||
sendMessage(message);
|
||||
}
|
||||
}
|
||||
|
||||
void sendMessage(String message);
|
||||
|
||||
/**
|
||||
* @return true if the specified sender is from the console.
|
||||
*/
|
||||
boolean isConsole();
|
||||
|
||||
/**
|
||||
* Returns the locale of the command sender. Defaults to the default locale at {@link LanguageUtils#getDefaultLocale()}.
|
||||
*
|
||||
* @return the locale of the command sender.
|
||||
*/
|
||||
default String getLocale() {
|
||||
return LanguageUtils.getDefaultLocale();
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if the CommandSender has a permission
|
||||
*
|
||||
* @param permission The permission node to check
|
||||
* @return true if the CommandSender has the requested permission, false if not
|
||||
*/
|
||||
boolean hasPermission(String permission);
|
||||
}
|
||||
|
|
@ -0,0 +1,89 @@
|
|||
/*
|
||||
* Copyright (c) 2019-2021 GeyserMC. http://geysermc.org
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*
|
||||
* @author GeyserMC
|
||||
* @link https://github.com/GeyserMC/Geyser
|
||||
*/
|
||||
|
||||
package org.geysermc.connector.command;
|
||||
|
||||
import lombok.Getter;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.Setter;
|
||||
import org.geysermc.connector.network.session.GeyserSession;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
@Getter
|
||||
@RequiredArgsConstructor
|
||||
public abstract class GeyserCommand {
|
||||
|
||||
protected final String name;
|
||||
/**
|
||||
* The description of the command - will attempt to be translated.
|
||||
*/
|
||||
protected final String description;
|
||||
protected final String permission;
|
||||
|
||||
@Setter
|
||||
private List<String> aliases = new ArrayList<>();
|
||||
|
||||
public abstract void execute(@Nullable GeyserSession session, CommandSender sender, String[] args);
|
||||
|
||||
/**
|
||||
* If false, hides the command from being shown on the Geyser Standalone GUI.
|
||||
*
|
||||
* @return true if the command can be run on the server console
|
||||
*/
|
||||
public boolean isExecutableOnConsole() {
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Used in the GUI to know what subcommands can be run
|
||||
*
|
||||
* @return a list of all possible subcommands, or empty if none.
|
||||
*/
|
||||
public List<String> getSubCommands() {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
/**
|
||||
* Shortcut to {@link #getSubCommands()}{@code .isEmpty()}.
|
||||
*
|
||||
* @return true if there are subcommand present for this command.
|
||||
*/
|
||||
public boolean hasSubCommands() {
|
||||
return !getSubCommands().isEmpty();
|
||||
}
|
||||
|
||||
/**
|
||||
* Used to send a deny message to Java players if this command can only be used by Bedrock players.
|
||||
*
|
||||
* @return true if this command can only be used by Bedrock players.
|
||||
*/
|
||||
public boolean isBedrockOnly() {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,53 @@
|
|||
/*
|
||||
* Copyright (c) 2019-2021 GeyserMC. http://geysermc.org
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*
|
||||
* @author GeyserMC
|
||||
* @link https://github.com/GeyserMC/Geyser
|
||||
*/
|
||||
|
||||
package org.geysermc.connector.command.defaults;
|
||||
|
||||
import org.geysermc.connector.command.CommandSender;
|
||||
import org.geysermc.connector.command.GeyserCommand;
|
||||
import org.geysermc.connector.network.session.GeyserSession;
|
||||
|
||||
public class AdvancementsCommand extends GeyserCommand {
|
||||
public AdvancementsCommand(String name, String description, String permission) {
|
||||
super(name, description, permission);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void execute(GeyserSession session, CommandSender sender, String[] args) {
|
||||
if (session != null) {
|
||||
session.getAdvancementsCache().buildAndShowMenuForm();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isExecutableOnConsole() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isBedrockOnly() {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,148 @@
|
|||
/*
|
||||
* Copyright (c) 2019-2021 GeyserMC. http://geysermc.org
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*
|
||||
* @author GeyserMC
|
||||
* @link https://github.com/GeyserMC/Geyser
|
||||
*/
|
||||
|
||||
package org.geysermc.connector.command.defaults;
|
||||
|
||||
import com.fasterxml.jackson.core.util.DefaultIndenter;
|
||||
import com.fasterxml.jackson.core.util.DefaultPrettyPrinter;
|
||||
import com.fasterxml.jackson.databind.JsonNode;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import org.geysermc.common.PlatformType;
|
||||
import org.geysermc.connector.GeyserConnector;
|
||||
import org.geysermc.connector.command.CommandSender;
|
||||
import org.geysermc.connector.command.GeyserCommand;
|
||||
import org.geysermc.connector.common.ChatColor;
|
||||
import org.geysermc.connector.common.serializer.AsteriskSerializer;
|
||||
import org.geysermc.connector.dump.DumpInfo;
|
||||
import org.geysermc.connector.network.session.GeyserSession;
|
||||
import org.geysermc.connector.utils.LanguageUtils;
|
||||
import org.geysermc.connector.utils.WebUtils;
|
||||
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
public class DumpCommand extends GeyserCommand {
|
||||
|
||||
private final GeyserConnector connector;
|
||||
private static final ObjectMapper MAPPER = new ObjectMapper();
|
||||
private static final String DUMP_URL = "https://dump.geysermc.org/";
|
||||
|
||||
public DumpCommand(GeyserConnector connector, String name, String description, String permission) {
|
||||
super(name, description, permission);
|
||||
|
||||
this.connector = connector;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void execute(GeyserSession session, CommandSender sender, String[] args) {
|
||||
// Only allow the console to create dumps on Geyser Standalone
|
||||
if (!sender.isConsole() && connector.getPlatformType() == PlatformType.STANDALONE) {
|
||||
sender.sendMessage(LanguageUtils.getPlayerLocaleString("geyser.bootstrap.command.permission_fail", sender.getLocale()));
|
||||
return;
|
||||
}
|
||||
|
||||
boolean showSensitive = false;
|
||||
boolean offlineDump = false;
|
||||
boolean addLog = false;
|
||||
if (args.length >= 1) {
|
||||
for (String arg : args) {
|
||||
switch (arg) {
|
||||
case "full" -> showSensitive = true;
|
||||
case "offline" -> offlineDump = true;
|
||||
case "logs" -> addLog = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
AsteriskSerializer.showSensitive = showSensitive;
|
||||
|
||||
sender.sendMessage(LanguageUtils.getPlayerLocaleString("geyser.commands.dump.collecting", sender.getLocale()));
|
||||
String dumpData;
|
||||
try {
|
||||
if (offlineDump) {
|
||||
DefaultPrettyPrinter prettyPrinter = new DefaultPrettyPrinter();
|
||||
// Make arrays easier to read
|
||||
prettyPrinter.indentArraysWith(new DefaultIndenter(" ", "\n"));
|
||||
dumpData = MAPPER.writer(prettyPrinter).writeValueAsString(new DumpInfo(addLog));
|
||||
} else {
|
||||
dumpData = MAPPER.writeValueAsString(new DumpInfo(addLog));
|
||||
}
|
||||
} catch (IOException e) {
|
||||
sender.sendMessage(ChatColor.RED + LanguageUtils.getPlayerLocaleString("geyser.commands.dump.collect_error", sender.getLocale()));
|
||||
connector.getLogger().error(LanguageUtils.getLocaleStringLog("geyser.commands.dump.collect_error_short"), e);
|
||||
return;
|
||||
}
|
||||
|
||||
String uploadedDumpUrl = "";
|
||||
|
||||
if (offlineDump) {
|
||||
sender.sendMessage(LanguageUtils.getPlayerLocaleString("geyser.commands.dump.writing", sender.getLocale()));
|
||||
|
||||
try {
|
||||
FileOutputStream outputStream = new FileOutputStream(GeyserConnector.getInstance().getBootstrap().getConfigFolder().resolve("dump.json").toFile());
|
||||
outputStream.write(dumpData.getBytes());
|
||||
outputStream.close();
|
||||
} catch (IOException e) {
|
||||
sender.sendMessage(ChatColor.RED + LanguageUtils.getPlayerLocaleString("geyser.commands.dump.write_error", sender.getLocale()));
|
||||
connector.getLogger().error(LanguageUtils.getLocaleStringLog("geyser.commands.dump.write_error_short"), e);
|
||||
return;
|
||||
}
|
||||
|
||||
uploadedDumpUrl = "dump.json";
|
||||
} else {
|
||||
sender.sendMessage(LanguageUtils.getPlayerLocaleString("geyser.commands.dump.uploading", sender.getLocale()));
|
||||
|
||||
String response;
|
||||
JsonNode responseNode;
|
||||
try {
|
||||
response = WebUtils.post(DUMP_URL + "documents", dumpData);
|
||||
responseNode = MAPPER.readTree(response);
|
||||
} catch (IOException e) {
|
||||
sender.sendMessage(ChatColor.RED + LanguageUtils.getPlayerLocaleString("geyser.commands.dump.upload_error", sender.getLocale()));
|
||||
connector.getLogger().error(LanguageUtils.getLocaleStringLog("geyser.commands.dump.upload_error_short"), e);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!responseNode.has("key")) {
|
||||
sender.sendMessage(ChatColor.RED + LanguageUtils.getPlayerLocaleString("geyser.commands.dump.upload_error_short", sender.getLocale()) + ": " + (responseNode.has("message") ? responseNode.get("message").asText() : response));
|
||||
return;
|
||||
}
|
||||
|
||||
uploadedDumpUrl = DUMP_URL + responseNode.get("key").asText();
|
||||
}
|
||||
|
||||
sender.sendMessage(LanguageUtils.getPlayerLocaleString("geyser.commands.dump.message", sender.getLocale()) + " " + ChatColor.DARK_AQUA + uploadedDumpUrl);
|
||||
if (!sender.isConsole()) {
|
||||
connector.getLogger().info(LanguageUtils.getLocaleStringLog("geyser.commands.dump.created", sender.getName(), uploadedDumpUrl));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<String> getSubCommands() {
|
||||
return Arrays.asList("offline", "full", "logs");
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,77 @@
|
|||
/*
|
||||
* Copyright (c) 2019-2021 GeyserMC. http://geysermc.org
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*
|
||||
* @author GeyserMC
|
||||
* @link https://github.com/GeyserMC/Geyser
|
||||
*/
|
||||
|
||||
package org.geysermc.connector.command.defaults;
|
||||
|
||||
import org.geysermc.connector.GeyserConnector;
|
||||
import org.geysermc.connector.command.CommandSender;
|
||||
import org.geysermc.connector.command.GeyserCommand;
|
||||
import org.geysermc.connector.common.ChatColor;
|
||||
import org.geysermc.connector.network.session.GeyserSession;
|
||||
import org.geysermc.connector.utils.LanguageUtils;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.Map;
|
||||
|
||||
public class HelpCommand extends GeyserCommand {
|
||||
private final GeyserConnector connector;
|
||||
|
||||
public HelpCommand(GeyserConnector connector, String name, String description, String permission) {
|
||||
super(name, description, permission);
|
||||
this.connector = connector;
|
||||
|
||||
this.setAliases(Collections.singletonList("?"));
|
||||
}
|
||||
|
||||
/**
|
||||
* Sends the help menu to a command sender. Will not show certain commands depending on the command sender and session.
|
||||
*
|
||||
* @param session The Geyser session of the command sender, if it is a bedrock player. If null, bedrock-only commands will be hidden.
|
||||
* @param sender The CommandSender to send the help message to.
|
||||
* @param args Not used.
|
||||
*/
|
||||
@Override
|
||||
public void execute(GeyserSession session, CommandSender sender, String[] args) {
|
||||
int page = 1;
|
||||
int maxPage = 1;
|
||||
String header = LanguageUtils.getPlayerLocaleString("geyser.commands.help.header", sender.getLocale(), page, maxPage);
|
||||
sender.sendMessage(header);
|
||||
|
||||
Map<String, GeyserCommand> cmds = connector.getCommandManager().getCommands();
|
||||
for (String cmdName : cmds.keySet()) {
|
||||
GeyserCommand cmd = cmds.get(cmdName);
|
||||
|
||||
if (sender.hasPermission(cmd.getPermission())) {
|
||||
// Only list commands the player can actually run
|
||||
if (cmd.isBedrockOnly() && session == null) {
|
||||
continue;
|
||||
}
|
||||
|
||||
sender.sendMessage(ChatColor.YELLOW + "/geyser " + cmdName + ChatColor.WHITE + ": " +
|
||||
LanguageUtils.getPlayerLocaleString(cmd.getDescription(), sender.getLocale()));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,54 @@
|
|||
/*
|
||||
* Copyright (c) 2019-2021 GeyserMC. http://geysermc.org
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*
|
||||
* @author GeyserMC
|
||||
* @link https://github.com/GeyserMC/Geyser
|
||||
*/
|
||||
|
||||
package org.geysermc.connector.command.defaults;
|
||||
|
||||
import org.geysermc.connector.GeyserConnector;
|
||||
import org.geysermc.connector.command.CommandSender;
|
||||
import org.geysermc.connector.command.GeyserCommand;
|
||||
import org.geysermc.connector.network.session.GeyserSession;
|
||||
import org.geysermc.connector.utils.LanguageUtils;
|
||||
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
public class ListCommand extends GeyserCommand {
|
||||
|
||||
private final GeyserConnector connector;
|
||||
|
||||
public ListCommand(GeyserConnector connector, String name, String description, String permission) {
|
||||
super(name, description, permission);
|
||||
|
||||
this.connector = connector;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void execute(GeyserSession session, CommandSender sender, String[] args) {
|
||||
String message = LanguageUtils.getPlayerLocaleString("geyser.commands.list.message", sender.getLocale(),
|
||||
connector.getSessionManager().size(),
|
||||
connector.getSessionManager().getAllSessions().stream().map(GeyserSession::getName).collect(Collectors.joining(" ")));
|
||||
|
||||
sender.sendMessage(message);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,63 @@
|
|||
/*
|
||||
* Copyright (c) 2019-2021 GeyserMC. http://geysermc.org
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*
|
||||
* @author GeyserMC
|
||||
* @link https://github.com/GeyserMC/Geyser
|
||||
*/
|
||||
|
||||
package org.geysermc.connector.command.defaults;
|
||||
|
||||
import com.github.steveice10.mc.protocol.data.game.entity.object.Direction;
|
||||
import com.github.steveice10.mc.protocol.data.game.entity.player.PlayerAction;
|
||||
import com.github.steveice10.mc.protocol.packet.ingame.serverbound.player.ServerboundPlayerActionPacket;
|
||||
import org.geysermc.connector.GeyserConnector;
|
||||
import org.geysermc.connector.command.CommandSender;
|
||||
import org.geysermc.connector.command.GeyserCommand;
|
||||
import org.geysermc.connector.network.session.GeyserSession;
|
||||
import org.geysermc.connector.utils.BlockUtils;
|
||||
|
||||
public class OffhandCommand extends GeyserCommand {
|
||||
|
||||
public OffhandCommand(GeyserConnector connector, String name, String description, String permission) {
|
||||
super(name, description, permission);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void execute(GeyserSession session, CommandSender sender, String[] args) {
|
||||
if (session == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
ServerboundPlayerActionPacket releaseItemPacket = new ServerboundPlayerActionPacket(PlayerAction.SWAP_HANDS, BlockUtils.POSITION_ZERO,
|
||||
Direction.DOWN);
|
||||
session.sendDownstreamPacket(releaseItemPacket);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isExecutableOnConsole() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isBedrockOnly() {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,57 @@
|
|||
/*
|
||||
* Copyright (c) 2019-2021 GeyserMC. http://geysermc.org
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*
|
||||
* @author GeyserMC
|
||||
* @link https://github.com/GeyserMC/Geyser
|
||||
*/
|
||||
|
||||
package org.geysermc.connector.command.defaults;
|
||||
|
||||
import org.geysermc.common.PlatformType;
|
||||
import org.geysermc.connector.GeyserConnector;
|
||||
import org.geysermc.connector.command.CommandSender;
|
||||
import org.geysermc.connector.command.GeyserCommand;
|
||||
import org.geysermc.connector.network.session.GeyserSession;
|
||||
import org.geysermc.connector.utils.LanguageUtils;
|
||||
|
||||
public class ReloadCommand extends GeyserCommand {
|
||||
|
||||
private final GeyserConnector connector;
|
||||
|
||||
public ReloadCommand(GeyserConnector connector, String name, String description, String permission) {
|
||||
super(name, description, permission);
|
||||
this.connector = connector;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void execute(GeyserSession session, CommandSender sender, String[] args) {
|
||||
if (!sender.isConsole() && connector.getPlatformType() == PlatformType.STANDALONE) {
|
||||
return;
|
||||
}
|
||||
|
||||
String message = LanguageUtils.getPlayerLocaleString("geyser.commands.reload.message", sender.getLocale());
|
||||
|
||||
sender.sendMessage(message);
|
||||
|
||||
connector.getSessionManager().disconnectAll("geyser.commands.reload.kick");
|
||||
connector.reload();
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,55 @@
|
|||
/*
|
||||
* Copyright (c) 2019-2021 GeyserMC. http://geysermc.org
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*
|
||||
* @author GeyserMC
|
||||
* @link https://github.com/GeyserMC/Geyser
|
||||
*/
|
||||
|
||||
package org.geysermc.connector.command.defaults;
|
||||
|
||||
import org.geysermc.connector.GeyserConnector;
|
||||
import org.geysermc.connector.command.CommandSender;
|
||||
import org.geysermc.connector.command.GeyserCommand;
|
||||
import org.geysermc.connector.network.session.GeyserSession;
|
||||
import org.geysermc.connector.utils.SettingsUtils;
|
||||
|
||||
public class SettingsCommand extends GeyserCommand {
|
||||
public SettingsCommand(GeyserConnector connector, String name, String description, String permission) {
|
||||
super(name, description, permission);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void execute(GeyserSession session, CommandSender sender, String[] args) {
|
||||
if (session != null) {
|
||||
session.sendForm(SettingsUtils.buildForm(session));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isExecutableOnConsole() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isBedrockOnly() {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,59 @@
|
|||
/*
|
||||
* Copyright (c) 2019-2021 GeyserMC. http://geysermc.org
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*
|
||||
* @author GeyserMC
|
||||
* @link https://github.com/GeyserMC/Geyser
|
||||
*/
|
||||
|
||||
package org.geysermc.connector.command.defaults;
|
||||
|
||||
import com.github.steveice10.mc.protocol.data.game.ClientCommand;
|
||||
import com.github.steveice10.mc.protocol.packet.ingame.serverbound.ServerboundClientCommandPacket;
|
||||
import org.geysermc.connector.GeyserConnector;
|
||||
import org.geysermc.connector.command.CommandSender;
|
||||
import org.geysermc.connector.command.GeyserCommand;
|
||||
import org.geysermc.connector.network.session.GeyserSession;
|
||||
|
||||
public class StatisticsCommand extends GeyserCommand {
|
||||
|
||||
public StatisticsCommand(GeyserConnector connector, String name, String description, String permission) {
|
||||
super(name, description, permission);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void execute(GeyserSession session, CommandSender sender, String[] args) {
|
||||
if (session == null) return;
|
||||
|
||||
session.setWaitingForStatistics(true);
|
||||
ServerboundClientCommandPacket ServerboundClientCommandPacket = new ServerboundClientCommandPacket(ClientCommand.STATS);
|
||||
session.sendDownstreamPacket(ServerboundClientCommandPacket);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isExecutableOnConsole() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isBedrockOnly() {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,57 @@
|
|||
/*
|
||||
* Copyright (c) 2019-2021 GeyserMC. http://geysermc.org
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*
|
||||
* @author GeyserMC
|
||||
* @link https://github.com/GeyserMC/Geyser
|
||||
*/
|
||||
|
||||
package org.geysermc.connector.command.defaults;
|
||||
|
||||
import org.geysermc.common.PlatformType;
|
||||
import org.geysermc.connector.GeyserConnector;
|
||||
import org.geysermc.connector.command.CommandSender;
|
||||
import org.geysermc.connector.command.GeyserCommand;
|
||||
import org.geysermc.connector.network.session.GeyserSession;
|
||||
import org.geysermc.connector.utils.LanguageUtils;
|
||||
|
||||
import java.util.Collections;
|
||||
|
||||
public class StopCommand extends GeyserCommand {
|
||||
|
||||
private final GeyserConnector connector;
|
||||
|
||||
public StopCommand(GeyserConnector connector, String name, String description, String permission) {
|
||||
super(name, description, permission);
|
||||
this.connector = connector;
|
||||
|
||||
this.setAliases(Collections.singletonList("shutdown"));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void execute(GeyserSession session, CommandSender sender, String[] args) {
|
||||
if (!sender.isConsole() && connector.getPlatformType() == PlatformType.STANDALONE) {
|
||||
sender.sendMessage(LanguageUtils.getPlayerLocaleString("geyser.bootstrap.command.permission_fail", sender.getLocale()));
|
||||
return;
|
||||
}
|
||||
|
||||
connector.getBootstrap().onDisable();
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,96 @@
|
|||
/*
|
||||
* Copyright (c) 2019-2021 GeyserMC. http://geysermc.org
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*
|
||||
* @author GeyserMC
|
||||
* @link https://github.com/GeyserMC/Geyser
|
||||
*/
|
||||
|
||||
package org.geysermc.connector.command.defaults;
|
||||
|
||||
import com.nukkitx.protocol.bedrock.BedrockPacketCodec;
|
||||
import org.geysermc.common.PlatformType;
|
||||
import org.geysermc.connector.GeyserConnector;
|
||||
import org.geysermc.connector.command.CommandSender;
|
||||
import org.geysermc.connector.command.GeyserCommand;
|
||||
import org.geysermc.connector.common.ChatColor;
|
||||
import org.geysermc.connector.network.MinecraftProtocol;
|
||||
import org.geysermc.connector.network.session.GeyserSession;
|
||||
import org.geysermc.connector.utils.FileUtils;
|
||||
import org.geysermc.connector.utils.LanguageUtils;
|
||||
import org.geysermc.connector.utils.WebUtils;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.net.URLEncoder;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.List;
|
||||
import java.util.Properties;
|
||||
|
||||
public class VersionCommand extends GeyserCommand {
|
||||
|
||||
private final GeyserConnector connector;
|
||||
|
||||
public VersionCommand(GeyserConnector connector, String name, String description, String permission) {
|
||||
super(name, description, permission);
|
||||
|
||||
this.connector = connector;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void execute(GeyserSession session, CommandSender sender, String[] args) {
|
||||
String bedrockVersions;
|
||||
List<BedrockPacketCodec> supportedCodecs = MinecraftProtocol.SUPPORTED_BEDROCK_CODECS;
|
||||
if (supportedCodecs.size() > 1) {
|
||||
bedrockVersions = supportedCodecs.get(0).getMinecraftVersion() + " - " + supportedCodecs.get(supportedCodecs.size() - 1).getMinecraftVersion();
|
||||
} else {
|
||||
bedrockVersions = MinecraftProtocol.SUPPORTED_BEDROCK_CODECS.get(0).getMinecraftVersion();
|
||||
}
|
||||
|
||||
sender.sendMessage(LanguageUtils.getPlayerLocaleString("geyser.commands.version.version", sender.getLocale(),
|
||||
GeyserConnector.NAME, GeyserConnector.VERSION, MinecraftProtocol.getJavaVersion(), bedrockVersions));
|
||||
|
||||
// Disable update checking in dev mode and for players in Geyser Standalone
|
||||
if (GeyserConnector.getInstance().isProductionEnvironment() && !(!sender.isConsole() && connector.getPlatformType() == PlatformType.STANDALONE)) {
|
||||
sender.sendMessage(LanguageUtils.getPlayerLocaleString("geyser.commands.version.checking", sender.getLocale()));
|
||||
try {
|
||||
Properties gitProp = new Properties();
|
||||
gitProp.load(FileUtils.getResource("git.properties"));
|
||||
|
||||
String buildXML = WebUtils.getBody("https://ci.opencollab.dev/job/GeyserMC/job/Geyser/job/" +
|
||||
URLEncoder.encode(gitProp.getProperty("git.branch"), StandardCharsets.UTF_8.toString()) + "/lastSuccessfulBuild/api/xml?xpath=//buildNumber");
|
||||
if (buildXML.startsWith("<buildNumber>")) {
|
||||
int latestBuildNum = Integer.parseInt(buildXML.replaceAll("<(\\\\)?(/)?buildNumber>", "").trim());
|
||||
int buildNum = Integer.parseInt(gitProp.getProperty("git.build.number"));
|
||||
if (latestBuildNum == buildNum) {
|
||||
sender.sendMessage(LanguageUtils.getPlayerLocaleString("geyser.commands.version.no_updates", sender.getLocale()));
|
||||
} else {
|
||||
sender.sendMessage(LanguageUtils.getPlayerLocaleString("geyser.commands.version.outdated",
|
||||
sender.getLocale(), (latestBuildNum - buildNum), "https://ci.geysermc.org/"));
|
||||
}
|
||||
} else {
|
||||
throw new AssertionError("buildNumber missing");
|
||||
}
|
||||
} catch (IOException | AssertionError | NumberFormatException e) {
|
||||
GeyserConnector.getInstance().getLogger().error(LanguageUtils.getLocaleStringLog("geyser.commands.version.failed"), e);
|
||||
sender.sendMessage(ChatColor.RED + LanguageUtils.getPlayerLocaleString("geyser.commands.version.failed", sender.getLocale()));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,70 @@
|
|||
/*
|
||||
* Copyright (c) 2019-2021 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.common;
|
||||
|
||||
import com.fasterxml.jackson.core.JsonParser;
|
||||
import com.fasterxml.jackson.databind.DeserializationContext;
|
||||
import com.fasterxml.jackson.databind.JsonDeserializer;
|
||||
import lombok.Getter;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
@Getter
|
||||
public enum AuthType {
|
||||
OFFLINE,
|
||||
ONLINE,
|
||||
FLOODGATE;
|
||||
|
||||
public static final AuthType[] VALUES = values();
|
||||
|
||||
public static AuthType getById(int id) {
|
||||
return id < VALUES.length ? VALUES[id] : OFFLINE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert the AuthType string (from config) to the enum, ONLINE on fail
|
||||
*
|
||||
* @param name AuthType string
|
||||
*
|
||||
* @return The converted AuthType
|
||||
*/
|
||||
public static AuthType getByName(String name) {
|
||||
String upperCase = name.toUpperCase();
|
||||
for (AuthType type : VALUES) {
|
||||
if (type.name().equals(upperCase)) {
|
||||
return type;
|
||||
}
|
||||
}
|
||||
return ONLINE;
|
||||
}
|
||||
|
||||
public static class Deserializer extends JsonDeserializer<AuthType> {
|
||||
@Override
|
||||
public AuthType deserialize(JsonParser p, DeserializationContext ctxt) throws IOException {
|
||||
return getByName(p.getValueAsString());
|
||||
}
|
||||
}
|
||||
}
|
||||
101
core/src/main/java/org/geysermc/connector/common/ChatColor.java
Normal file
101
core/src/main/java/org/geysermc/connector/common/ChatColor.java
Normal file
|
|
@ -0,0 +1,101 @@
|
|||
/*
|
||||
* Copyright (c) 2019-2021 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.common;
|
||||
|
||||
public class ChatColor {
|
||||
|
||||
public static final char ESCAPE = '§';
|
||||
public static final String BLACK = ESCAPE + "0";
|
||||
public static final String DARK_BLUE = ESCAPE + "1";
|
||||
public static final String DARK_GREEN = ESCAPE + "2";
|
||||
public static final String DARK_AQUA = ESCAPE + "3";
|
||||
public static final String DARK_RED = ESCAPE + "4";
|
||||
public static final String DARK_PURPLE = ESCAPE + "5";
|
||||
public static final String GOLD = ESCAPE + "6";
|
||||
public static final String GRAY = ESCAPE + "7";
|
||||
public static final String DARK_GRAY = ESCAPE + "8";
|
||||
public static final String BLUE = ESCAPE + "9";
|
||||
public static final String GREEN = ESCAPE + "a";
|
||||
public static final String AQUA = ESCAPE + "b";
|
||||
public static final String RED = ESCAPE + "c";
|
||||
public static final String LIGHT_PURPLE = ESCAPE + "d";
|
||||
public static final String YELLOW = ESCAPE + "e";
|
||||
public static final String WHITE = ESCAPE + "f";
|
||||
public static final String OBFUSCATED = ESCAPE + "k";
|
||||
public static final String BOLD = ESCAPE + "l";
|
||||
public static final String STRIKETHROUGH = ESCAPE + "m";
|
||||
public static final String UNDERLINE = ESCAPE + "n";
|
||||
public static final String ITALIC = ESCAPE + "o";
|
||||
public static final String RESET = ESCAPE + "r";
|
||||
|
||||
/**
|
||||
* Convert chat colour codes to terminal colours
|
||||
*
|
||||
* @param string The text to replace colours for
|
||||
*
|
||||
* @return A string ready for terminal printing
|
||||
*/
|
||||
public static String toANSI(String string) {
|
||||
string = string.replace(BOLD, (char) 0x1b + "[1m");
|
||||
string = string.replace(OBFUSCATED, (char) 0x1b + "[5m");
|
||||
string = string.replace(ITALIC, (char) 0x1b + "[3m");
|
||||
string = string.replace(UNDERLINE, (char) 0x1b + "[4m");
|
||||
string = string.replace(STRIKETHROUGH, (char) 0x1b + "[9m");
|
||||
string = string.replace(RESET, (char) 0x1b + "[0m");
|
||||
string = string.replace(BLACK, (char) 0x1b + "[0;30m");
|
||||
string = string.replace(DARK_BLUE, (char) 0x1b + "[0;34m");
|
||||
string = string.replace(DARK_GREEN, (char) 0x1b + "[0;32m");
|
||||
string = string.replace(DARK_AQUA, (char) 0x1b + "[0;36m");
|
||||
string = string.replace(DARK_RED, (char) 0x1b + "[0;31m");
|
||||
string = string.replace(DARK_PURPLE, (char) 0x1b + "[0;35m");
|
||||
string = string.replace(GOLD, (char) 0x1b + "[0;33m");
|
||||
string = string.replace(GRAY, (char) 0x1b + "[0;37m");
|
||||
string = string.replace(DARK_GRAY, (char) 0x1b + "[30;1m");
|
||||
string = string.replace(BLUE, (char) 0x1b + "[34;1m");
|
||||
string = string.replace(GREEN, (char) 0x1b + "[32;1m");
|
||||
string = string.replace(AQUA, (char) 0x1b + "[36;1m");
|
||||
string = string.replace(RED, (char) 0x1b + "[31;1m");
|
||||
string = string.replace(LIGHT_PURPLE, (char) 0x1b + "[35;1m");
|
||||
string = string.replace(YELLOW, (char) 0x1b + "[33;1m");
|
||||
string = string.replace(WHITE, (char) 0x1b + "[37;1m");
|
||||
return string;
|
||||
}
|
||||
|
||||
public String translateAlternateColorCodes(char color, String message) {
|
||||
return message.replace(color, ESCAPE);
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove all colour formatting tags from a message
|
||||
*
|
||||
* @param message Message to remove colour tags from
|
||||
*
|
||||
* @return The sanitised message
|
||||
*/
|
||||
public static String stripColors(String message) {
|
||||
return message = message.replaceAll("(&([a-fk-or0-9]))","").replaceAll("(§([a-fk-or0-9]))","").replaceAll("s/\\x1b\\[[0-9;]*[a-zA-Z]//g","");
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,265 @@
|
|||
/*
|
||||
* Copyright (c) 2019-2021 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.common.connection;
|
||||
|
||||
import io.netty.buffer.ByteBufAllocator;
|
||||
import io.netty.channel.*;
|
||||
import io.netty.util.Attribute;
|
||||
import io.netty.util.AttributeKey;
|
||||
|
||||
import java.net.SocketAddress;
|
||||
|
||||
public class ChannelWrapper implements Channel {
|
||||
protected final Channel source;
|
||||
private volatile SocketAddress remoteAddress;
|
||||
|
||||
public ChannelWrapper(Channel channel) {
|
||||
this.source = channel;
|
||||
}
|
||||
|
||||
@Override
|
||||
public SocketAddress localAddress() {
|
||||
return source.localAddress();
|
||||
}
|
||||
|
||||
@Override
|
||||
public SocketAddress remoteAddress() {
|
||||
if (remoteAddress == null) {
|
||||
return source.remoteAddress();
|
||||
}
|
||||
return remoteAddress;
|
||||
}
|
||||
|
||||
public void remoteAddress(SocketAddress socketAddress) {
|
||||
remoteAddress = socketAddress;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ChannelId id() {
|
||||
return source.id();
|
||||
}
|
||||
|
||||
@Override
|
||||
public EventLoop eventLoop() {
|
||||
return source.eventLoop();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Channel parent() {
|
||||
return source.parent();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ChannelConfig config() {
|
||||
return source.config();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isOpen() {
|
||||
return source.isOpen();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isRegistered() {
|
||||
return source.isRegistered();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isActive() {
|
||||
return source.isActive();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ChannelMetadata metadata() {
|
||||
return source.metadata();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ChannelFuture closeFuture() {
|
||||
return source.closeFuture();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isWritable() {
|
||||
return source.isWritable();
|
||||
}
|
||||
|
||||
@Override
|
||||
public long bytesBeforeUnwritable() {
|
||||
return source.bytesBeforeUnwritable();
|
||||
}
|
||||
|
||||
@Override
|
||||
public long bytesBeforeWritable() {
|
||||
return source.bytesBeforeWritable();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Unsafe unsafe() {
|
||||
return source.unsafe();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ChannelPipeline pipeline() {
|
||||
return source.pipeline();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ByteBufAllocator alloc() {
|
||||
return source.alloc();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ChannelFuture bind(SocketAddress socketAddress) {
|
||||
return source.bind(socketAddress);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ChannelFuture connect(SocketAddress socketAddress) {
|
||||
return source.connect(socketAddress);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ChannelFuture connect(SocketAddress socketAddress, SocketAddress socketAddress1) {
|
||||
return source.connect(socketAddress, socketAddress1);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ChannelFuture disconnect() {
|
||||
return source.disconnect();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ChannelFuture close() {
|
||||
return source.disconnect();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ChannelFuture deregister() {
|
||||
return source.deregister();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ChannelFuture bind(SocketAddress socketAddress, ChannelPromise channelPromise) {
|
||||
return source.bind(socketAddress, channelPromise);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ChannelFuture connect(SocketAddress socketAddress, ChannelPromise channelPromise) {
|
||||
return source.connect(socketAddress, channelPromise);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ChannelFuture connect(SocketAddress socketAddress, SocketAddress socketAddress1, ChannelPromise channelPromise) {
|
||||
return source.connect(socketAddress, socketAddress1, channelPromise);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ChannelFuture disconnect(ChannelPromise channelPromise) {
|
||||
return source.disconnect(channelPromise);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ChannelFuture close(ChannelPromise channelPromise) {
|
||||
return source.close(channelPromise);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ChannelFuture deregister(ChannelPromise channelPromise) {
|
||||
return source.deregister(channelPromise);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Channel read() {
|
||||
source.read();
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ChannelFuture write(Object o) {
|
||||
return source.write(o);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ChannelFuture write(Object o, ChannelPromise channelPromise) {
|
||||
return source.write(o, channelPromise);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Channel flush() {
|
||||
return source.flush();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ChannelFuture writeAndFlush(Object o, ChannelPromise channelPromise) {
|
||||
return source.writeAndFlush(o, channelPromise);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ChannelFuture writeAndFlush(Object o) {
|
||||
return source.writeAndFlush(o);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ChannelPromise newPromise() {
|
||||
return source.newPromise();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ChannelProgressivePromise newProgressivePromise() {
|
||||
return source.newProgressivePromise();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ChannelFuture newSucceededFuture() {
|
||||
return source.newSucceededFuture();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ChannelFuture newFailedFuture(Throwable throwable) {
|
||||
return source.newFailedFuture(throwable);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ChannelPromise voidPromise() {
|
||||
return source.voidPromise();
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> Attribute<T> attr(AttributeKey<T> attributeKey) {
|
||||
return source.attr(attributeKey);
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> boolean hasAttr(AttributeKey<T> attributeKey) {
|
||||
return source.hasAttr(attributeKey);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int compareTo(Channel o) {
|
||||
return source.compareTo(o);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,38 @@
|
|||
/*
|
||||
* Copyright (c) 2019-2021 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.common.connection;
|
||||
|
||||
import io.netty.channel.Channel;
|
||||
import io.netty.channel.DefaultChannelPipeline;
|
||||
|
||||
/**
|
||||
* Exists solely to make DefaultChannelPipeline's protected constructor public
|
||||
*/
|
||||
public class DefaultChannelPipelinePublic extends DefaultChannelPipeline {
|
||||
public DefaultChannelPipelinePublic(Channel channel) {
|
||||
super(channel);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,90 @@
|
|||
/*
|
||||
* Copyright (c) 2019-2021 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.common.connection;
|
||||
|
||||
import io.netty.channel.ChannelFuture;
|
||||
import lombok.Getter;
|
||||
import org.geysermc.connector.bootstrap.GeyserBootstrap;
|
||||
|
||||
import java.net.SocketAddress;
|
||||
|
||||
/**
|
||||
* Used to inject Geyser clients directly into the server, bypassing the need to implement a complete TCP connection,
|
||||
* by creating a local channel.
|
||||
*/
|
||||
public abstract class GeyserInjector {
|
||||
/**
|
||||
* The local channel we can use to inject ourselves into the server without creating a TCP connection.
|
||||
*/
|
||||
protected ChannelFuture localChannel;
|
||||
/**
|
||||
* The LocalAddress to use to connect to the server without connecting over TCP.
|
||||
*/
|
||||
@Getter
|
||||
protected SocketAddress serverSocketAddress;
|
||||
|
||||
/**
|
||||
* @param bootstrap the bootstrap of the Geyser instance.
|
||||
*/
|
||||
public void initializeLocalChannel(GeyserBootstrap bootstrap) {
|
||||
if (!bootstrap.getGeyserConfig().isUseDirectConnection()) {
|
||||
bootstrap.getGeyserLogger().debug("Disabling direct injection!");
|
||||
return;
|
||||
}
|
||||
|
||||
if (this.localChannel != null) {
|
||||
bootstrap.getGeyserLogger().warning("Geyser attempted to inject into the server connection handler twice! Please ensure you aren't using /reload or any plugin that (re)loads Geyser after the server has started.");
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
initializeLocalChannel0(bootstrap);
|
||||
bootstrap.getGeyserLogger().debug("Local injection succeeded!");
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
// If the injector partially worked, undo it
|
||||
shutdown();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* The method to implement that is called by {@link #initializeLocalChannel(GeyserBootstrap)} wrapped around a try/catch.
|
||||
*/
|
||||
protected abstract void initializeLocalChannel0(GeyserBootstrap bootstrap) throws Exception;
|
||||
|
||||
public void shutdown() {
|
||||
if (localChannel != null && localChannel.channel().isOpen()) {
|
||||
try {
|
||||
localChannel.channel().close().sync();
|
||||
localChannel = null;
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
} else if (localChannel != null) {
|
||||
localChannel = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,45 @@
|
|||
/*
|
||||
* Copyright (c) 2019-2021 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.common.connection;
|
||||
|
||||
import io.netty.channel.local.LocalChannel;
|
||||
|
||||
import java.net.InetSocketAddress;
|
||||
|
||||
/**
|
||||
* Client -> server storing the spoofed remote address.
|
||||
*/
|
||||
public class LocalChannelWithRemoteAddress extends LocalChannel {
|
||||
private InetSocketAddress spoofedAddress;
|
||||
|
||||
public InetSocketAddress spoofedRemoteAddress() {
|
||||
return spoofedAddress;
|
||||
}
|
||||
|
||||
public void spoofedRemoteAddress(InetSocketAddress socketAddress) {
|
||||
this.spoofedAddress = socketAddress;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,70 @@
|
|||
/*
|
||||
* Copyright (c) 2019-2021 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.common.connection;
|
||||
|
||||
import io.netty.channel.DefaultChannelPipeline;
|
||||
import io.netty.channel.local.LocalChannel;
|
||||
import io.netty.channel.local.LocalServerChannel;
|
||||
|
||||
import java.net.InetSocketAddress;
|
||||
|
||||
public class LocalChannelWrapper extends LocalChannel {
|
||||
private final ChannelWrapper wrapper;
|
||||
/**
|
||||
* {@link #newChannelPipeline()} is called during super, so this exists until the wrapper can be initialized.
|
||||
*/
|
||||
private volatile ChannelWrapper tempWrapper;
|
||||
|
||||
public LocalChannelWrapper() {
|
||||
wrapper = new ChannelWrapper(this);
|
||||
}
|
||||
|
||||
public LocalChannelWrapper(LocalServerChannel parent, LocalChannel peer) {
|
||||
super(parent, peer);
|
||||
if (tempWrapper == null) {
|
||||
this.wrapper = new ChannelWrapper(this);
|
||||
} else {
|
||||
this.wrapper = tempWrapper;
|
||||
}
|
||||
wrapper.remoteAddress(new InetSocketAddress(0));
|
||||
}
|
||||
|
||||
public ChannelWrapper wrapper() {
|
||||
return wrapper;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected DefaultChannelPipeline newChannelPipeline() {
|
||||
if (wrapper != null) {
|
||||
return new DefaultChannelPipelinePublic(wrapper);
|
||||
} else if (tempWrapper != null) {
|
||||
return new DefaultChannelPipelinePublic(tempWrapper);
|
||||
} else {
|
||||
tempWrapper = new ChannelWrapper(this);
|
||||
return new DefaultChannelPipelinePublic(tempWrapper);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,46 @@
|
|||
/*
|
||||
* Copyright (c) 2019-2021 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.common.connection;
|
||||
|
||||
import io.netty.channel.local.LocalChannel;
|
||||
import io.netty.channel.local.LocalServerChannel;
|
||||
|
||||
/**
|
||||
* If the incoming channel if an instance of LocalChannelWithRemoteAddress, this server creates a LocalChannelWrapper
|
||||
* for the other end and attaches the spoofed remote address
|
||||
*/
|
||||
public class LocalServerChannelWrapper extends LocalServerChannel {
|
||||
@Override
|
||||
protected LocalChannel newLocalChannel(LocalChannel peer) {
|
||||
// LocalChannel here should be an instance of LocalChannelWithRemoteAddress, which we can use to set the "remote address" on the other end
|
||||
if (peer instanceof LocalChannelWithRemoteAddress) {
|
||||
LocalChannelWrapper channel = new LocalChannelWrapper(this, peer);
|
||||
channel.wrapper().remoteAddress(((LocalChannelWithRemoteAddress) peer).spoofedRemoteAddress());
|
||||
return channel;
|
||||
}
|
||||
return super.newLocalChannel(peer);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,142 @@
|
|||
/*
|
||||
* Copyright (c) 2019-2021 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.common.connection;
|
||||
|
||||
import com.github.steveice10.packetlib.BuiltinFlags;
|
||||
import com.github.steveice10.packetlib.packet.PacketProtocol;
|
||||
import com.github.steveice10.packetlib.tcp.*;
|
||||
import io.netty.bootstrap.Bootstrap;
|
||||
import io.netty.buffer.ByteBufAllocator;
|
||||
import io.netty.channel.*;
|
||||
import io.netty.channel.unix.PreferredDirectByteBufAllocator;
|
||||
import io.netty.handler.codec.haproxy.*;
|
||||
|
||||
import java.net.Inet4Address;
|
||||
import java.net.InetSocketAddress;
|
||||
import java.net.SocketAddress;
|
||||
|
||||
/**
|
||||
* Manages a Minecraft Java session over our LocalChannel implementations.
|
||||
*/
|
||||
public final class LocalSession extends TcpSession {
|
||||
private static DefaultEventLoopGroup DEFAULT_EVENT_LOOP_GROUP;
|
||||
private static PreferredDirectByteBufAllocator PREFERRED_DIRECT_BYTE_BUF_ALLOCATOR = null;
|
||||
|
||||
private final SocketAddress targetAddress;
|
||||
private final String clientIp;
|
||||
|
||||
public LocalSession(String host, int port, SocketAddress targetAddress, String clientIp, PacketProtocol protocol) {
|
||||
super(host, port, protocol);
|
||||
this.targetAddress = targetAddress;
|
||||
this.clientIp = clientIp;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void connect() {
|
||||
if (this.disconnected) {
|
||||
throw new IllegalStateException("Session has already been disconnected.");
|
||||
}
|
||||
|
||||
if (DEFAULT_EVENT_LOOP_GROUP == null) {
|
||||
DEFAULT_EVENT_LOOP_GROUP = new DefaultEventLoopGroup();
|
||||
}
|
||||
|
||||
try {
|
||||
final Bootstrap bootstrap = new Bootstrap();
|
||||
bootstrap.channel(LocalChannelWithRemoteAddress.class);
|
||||
bootstrap.handler(new ChannelInitializer<LocalChannelWithRemoteAddress>() {
|
||||
@Override
|
||||
public void initChannel(LocalChannelWithRemoteAddress channel) {
|
||||
channel.spoofedRemoteAddress(new InetSocketAddress(clientIp, 0));
|
||||
getPacketProtocol().newClientSession(LocalSession.this);
|
||||
|
||||
refreshReadTimeoutHandler(channel);
|
||||
refreshWriteTimeoutHandler(channel);
|
||||
|
||||
ChannelPipeline pipeline = channel.pipeline();
|
||||
pipeline.addLast("encryption", new TcpPacketEncryptor(LocalSession.this));
|
||||
pipeline.addLast("sizer", new TcpPacketSizer(LocalSession.this));
|
||||
pipeline.addLast("codec", new TcpPacketCodec(LocalSession.this));
|
||||
pipeline.addLast("manager", LocalSession.this);
|
||||
|
||||
addHAProxySupport(pipeline);
|
||||
}
|
||||
}).group(DEFAULT_EVENT_LOOP_GROUP).option(ChannelOption.CONNECT_TIMEOUT_MILLIS, getConnectTimeout() * 1000);
|
||||
|
||||
if (PREFERRED_DIRECT_BYTE_BUF_ALLOCATOR != null) {
|
||||
bootstrap.option(ChannelOption.ALLOCATOR, PREFERRED_DIRECT_BYTE_BUF_ALLOCATOR);
|
||||
}
|
||||
|
||||
bootstrap.remoteAddress(targetAddress);
|
||||
|
||||
bootstrap.connect().addListener((future) -> {
|
||||
if (!future.isSuccess()) {
|
||||
exceptionCaught(null, future.cause());
|
||||
}
|
||||
});
|
||||
} catch (Throwable t) {
|
||||
exceptionCaught(null, t);
|
||||
}
|
||||
}
|
||||
|
||||
// TODO duplicate code
|
||||
private void addHAProxySupport(ChannelPipeline pipeline) {
|
||||
InetSocketAddress clientAddress = getFlag(BuiltinFlags.CLIENT_PROXIED_ADDRESS);
|
||||
if (getFlag(BuiltinFlags.ENABLE_CLIENT_PROXY_PROTOCOL, false) && clientAddress != null) {
|
||||
pipeline.addFirst("proxy-protocol-packet-sender", new ChannelInboundHandlerAdapter() {
|
||||
@Override
|
||||
public void channelActive(ChannelHandlerContext ctx) throws Exception {
|
||||
HAProxyProxiedProtocol proxiedProtocol = clientAddress.getAddress() instanceof Inet4Address ? HAProxyProxiedProtocol.TCP4 : HAProxyProxiedProtocol.TCP6;
|
||||
InetSocketAddress remoteAddress;
|
||||
if (ctx.channel().remoteAddress() instanceof InetSocketAddress) {
|
||||
remoteAddress = (InetSocketAddress) ctx.channel().remoteAddress();
|
||||
} else {
|
||||
remoteAddress = new InetSocketAddress(host, port);
|
||||
}
|
||||
ctx.channel().writeAndFlush(new HAProxyMessage(
|
||||
HAProxyProtocolVersion.V2, HAProxyCommand.PROXY, proxiedProtocol,
|
||||
clientAddress.getAddress().getHostAddress(), remoteAddress.getAddress().getHostAddress(),
|
||||
clientAddress.getPort(), remoteAddress.getPort()
|
||||
));
|
||||
ctx.pipeline().remove(this);
|
||||
ctx.pipeline().remove("proxy-protocol-encoder");
|
||||
super.channelActive(ctx);
|
||||
}
|
||||
});
|
||||
pipeline.addFirst("proxy-protocol-encoder", HAProxyMessageEncoder.INSTANCE);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Should only be called when direct ByteBufs should be preferred. At this moment, this should only be called on BungeeCord.
|
||||
*/
|
||||
public static void createDirectByteBufAllocator() {
|
||||
if (PREFERRED_DIRECT_BYTE_BUF_ALLOCATOR == null) {
|
||||
PREFERRED_DIRECT_BYTE_BUF_ALLOCATOR = new PreferredDirectByteBufAllocator();
|
||||
PREFERRED_DIRECT_BYTE_BUF_ALLOCATOR.updateAllocator(ByteBufAllocator.DEFAULT);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,119 @@
|
|||
/*
|
||||
* Copyright (c) 2019-2021 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.common.main;
|
||||
|
||||
import javax.swing.*;
|
||||
import java.io.InputStream;
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.Locale;
|
||||
import java.util.Scanner;
|
||||
|
||||
public class IGeyserMain {
|
||||
|
||||
/**
|
||||
* Displays the run help message in the console and a message box if running with a gui
|
||||
*/
|
||||
public void displayMessage() {
|
||||
String message = createMessage();
|
||||
|
||||
if (System.console() == null && !isHeadless()) {
|
||||
JOptionPane.showMessageDialog(null, message, "GeyserMC Plugin: " + this.getPluginType(), JOptionPane.ERROR_MESSAGE);
|
||||
}
|
||||
|
||||
printMessage(message);
|
||||
}
|
||||
|
||||
/**
|
||||
* Load and format the run help text
|
||||
*
|
||||
* @return The formatted message
|
||||
*/
|
||||
private String createMessage() {
|
||||
StringBuilder message = new StringBuilder();
|
||||
|
||||
InputStream helpStream = IGeyserMain.class.getClassLoader().getResourceAsStream("languages/run-help/" + Locale.getDefault().toString() + ".txt");
|
||||
|
||||
if (helpStream == null) {
|
||||
helpStream = IGeyserMain.class.getClassLoader().getResourceAsStream("languages/run-help/en_US.txt");
|
||||
}
|
||||
|
||||
Scanner help = new Scanner(helpStream).useDelimiter("\\Z");
|
||||
String line = "";
|
||||
while (help.hasNext()) {
|
||||
line = help.next();
|
||||
|
||||
line = line.replace("${plugin_type}", this.getPluginType());
|
||||
line = line.replace("${plugin_folder}", this.getPluginFolder());
|
||||
|
||||
message.append(line).append("\n");
|
||||
}
|
||||
|
||||
return message.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if we are in a headless environment
|
||||
*
|
||||
* @return Are we in a headless environment?
|
||||
*/
|
||||
private boolean isHeadless() {
|
||||
try {
|
||||
Class<?> graphicsEnvironment = Class.forName("java.awt.GraphicsEnvironment");
|
||||
Method isHeadless = graphicsEnvironment.getDeclaredMethod("isHeadless");
|
||||
return (Boolean)isHeadless.invoke(null);
|
||||
} catch (Exception ignored) {
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Simply print a message to console
|
||||
*
|
||||
* @param message The message to print
|
||||
*/
|
||||
private void printMessage(String message) {
|
||||
System.out.print(message);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the platform the plugin is for
|
||||
*
|
||||
* @return The string representation of the plugin platforms name
|
||||
*/
|
||||
public String getPluginType() {
|
||||
return "unknown";
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the folder name the plugin should go into
|
||||
*
|
||||
* @return The string representation of the folder
|
||||
*/
|
||||
public String getPluginFolder() {
|
||||
return "unknown";
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,93 @@
|
|||
/*
|
||||
* Copyright (c) 2019-2021 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.common.ping;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonIgnore;
|
||||
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
|
||||
import com.fasterxml.jackson.annotation.JsonSetter;
|
||||
import com.fasterxml.jackson.databind.JsonNode;
|
||||
import lombok.Data;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
|
||||
@Data
|
||||
@JsonIgnoreProperties(ignoreUnknown = true)
|
||||
public class GeyserPingInfo {
|
||||
|
||||
private String description;
|
||||
|
||||
private Players players;
|
||||
private Version version;
|
||||
|
||||
@JsonIgnore
|
||||
private Collection<String> playerList = new ArrayList<>();
|
||||
|
||||
public GeyserPingInfo() {
|
||||
}
|
||||
|
||||
public GeyserPingInfo(String description, Players players, Version version) {
|
||||
this.description = description;
|
||||
this.players = players;
|
||||
this.version = version;
|
||||
}
|
||||
|
||||
@JsonSetter("description")
|
||||
void setDescription(JsonNode description) {
|
||||
this.description = description.toString();
|
||||
}
|
||||
|
||||
@Data
|
||||
@JsonIgnoreProperties(ignoreUnknown = true)
|
||||
public static class Players {
|
||||
|
||||
private int max;
|
||||
private int online;
|
||||
|
||||
public Players() {
|
||||
}
|
||||
|
||||
public Players(int max, int online) {
|
||||
this.max = max;
|
||||
this.online = online;
|
||||
}
|
||||
}
|
||||
|
||||
@Data
|
||||
public static class Version {
|
||||
|
||||
private String name;
|
||||
private int protocol;
|
||||
|
||||
public Version() {
|
||||
}
|
||||
|
||||
public Version(String name, int protocol) {
|
||||
this.name = name;
|
||||
this.protocol = protocol;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,101 @@
|
|||
/*
|
||||
* Copyright (c) 2019-2021 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.common.serializer;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JacksonAnnotationsInside;
|
||||
import com.fasterxml.jackson.core.JsonGenerator;
|
||||
import com.fasterxml.jackson.databind.BeanProperty;
|
||||
import com.fasterxml.jackson.databind.JsonSerializer;
|
||||
import com.fasterxml.jackson.databind.SerializerProvider;
|
||||
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
|
||||
import com.fasterxml.jackson.databind.ser.ContextualSerializer;
|
||||
import com.fasterxml.jackson.databind.ser.std.StdSerializer;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
import java.util.Optional;
|
||||
|
||||
public class AsteriskSerializer extends StdSerializer<Object> implements ContextualSerializer {
|
||||
|
||||
public static boolean showSensitive = false;
|
||||
|
||||
@Target({ElementType.FIELD})
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@JacksonAnnotationsInside
|
||||
@JsonSerialize(using = AsteriskSerializer.class)
|
||||
public @interface Asterisk {
|
||||
String value() default "***";
|
||||
/**
|
||||
* If true, this value will be shown if {@link #showSensitive} is true, or if the IP is determined to not be a public IP
|
||||
*
|
||||
* @return true if this should be analyzed and treated as an IP
|
||||
*/
|
||||
boolean isIp() default false;
|
||||
}
|
||||
|
||||
String asterisk;
|
||||
boolean isIp;
|
||||
|
||||
public AsteriskSerializer() {
|
||||
super(Object.class);
|
||||
}
|
||||
|
||||
public AsteriskSerializer(String asterisk, boolean isIp) {
|
||||
super(Object.class);
|
||||
this.asterisk = asterisk;
|
||||
this.isIp = isIp;
|
||||
}
|
||||
|
||||
@Override
|
||||
public JsonSerializer<?> createContextual(SerializerProvider serializerProvider, BeanProperty property) {
|
||||
Optional<Asterisk> anno = Optional.ofNullable(property)
|
||||
.map(prop -> prop.getAnnotation(Asterisk.class));
|
||||
|
||||
return new AsteriskSerializer(anno.map(Asterisk::value).orElse(null), anno.map(Asterisk::isIp).orElse(null));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void serialize(Object obj, JsonGenerator gen, SerializerProvider prov) throws IOException {
|
||||
if (isIp && (showSensitive || !isSensitiveIp((String) obj))) {
|
||||
gen.writeObject(obj);
|
||||
return;
|
||||
}
|
||||
|
||||
gen.writeString(asterisk);
|
||||
}
|
||||
|
||||
private boolean isSensitiveIp(String ip) {
|
||||
if (ip.equalsIgnoreCase("localhost") || ip.equalsIgnoreCase("auto")) {
|
||||
// `auto` should not be shown unless there is an obscure issue with setting the localhost address
|
||||
return false;
|
||||
}
|
||||
|
||||
return !ip.isEmpty() && !ip.equals("0.0.0.0") && !ip.equals("127.0.0.1");
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,50 @@
|
|||
/*
|
||||
* Copyright (c) 2019-2021 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.configuration;
|
||||
|
||||
import com.fasterxml.jackson.core.JsonParser;
|
||||
import com.fasterxml.jackson.databind.DeserializationContext;
|
||||
import com.fasterxml.jackson.databind.JsonDeserializer;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
public enum EmoteOffhandWorkaroundOption {
|
||||
NO_EMOTES,
|
||||
EMOTES_AND_OFFHAND,
|
||||
DISABLED;
|
||||
|
||||
public static class Deserializer extends JsonDeserializer<EmoteOffhandWorkaroundOption> {
|
||||
@Override
|
||||
public EmoteOffhandWorkaroundOption deserialize(JsonParser p, DeserializationContext ctxt) throws IOException {
|
||||
String value = p.getValueAsString();
|
||||
return switch (value) {
|
||||
case "no-emotes" -> NO_EMOTES;
|
||||
case "emotes-and-offhand" -> EMOTES_AND_OFFHAND;
|
||||
default -> DISABLED;
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,181 @@
|
|||
/*
|
||||
* Copyright (c) 2019-2021 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.configuration;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonIgnore;
|
||||
import org.geysermc.connector.GeyserLogger;
|
||||
import org.geysermc.connector.common.AuthType;
|
||||
import org.geysermc.connector.network.CIDRMatcher;
|
||||
import org.geysermc.connector.utils.LanguageUtils;
|
||||
|
||||
import java.nio.file.Path;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
public interface GeyserConfiguration {
|
||||
|
||||
// Modify this when you introduce breaking changes into the config
|
||||
int CURRENT_CONFIG_VERSION = 4;
|
||||
|
||||
IBedrockConfiguration getBedrock();
|
||||
|
||||
IRemoteConfiguration getRemote();
|
||||
|
||||
Map<String, ? extends IUserAuthenticationInfo> getUserAuths();
|
||||
|
||||
boolean isCommandSuggestions();
|
||||
|
||||
@JsonIgnore
|
||||
boolean isPassthroughMotd();
|
||||
|
||||
@JsonIgnore
|
||||
boolean isPassthroughProtocolName();
|
||||
|
||||
@JsonIgnore
|
||||
boolean isPassthroughPlayerCounts();
|
||||
|
||||
@JsonIgnore
|
||||
boolean isLegacyPingPassthrough();
|
||||
|
||||
int getPingPassthroughInterval();
|
||||
|
||||
boolean isForwardPlayerPing();
|
||||
|
||||
int getMaxPlayers();
|
||||
|
||||
boolean isDebugMode();
|
||||
|
||||
boolean isAllowThirdPartyCapes();
|
||||
|
||||
boolean isAllowThirdPartyEars();
|
||||
|
||||
String getShowCooldown();
|
||||
|
||||
boolean isShowCoordinates();
|
||||
|
||||
EmoteOffhandWorkaroundOption getEmoteOffhandWorkaround();
|
||||
|
||||
String getDefaultLocale();
|
||||
|
||||
Path getFloodgateKeyPath();
|
||||
|
||||
boolean isAddNonBedrockItems();
|
||||
|
||||
boolean isAboveBedrockNetherBuilding();
|
||||
|
||||
boolean isForceResourcePacks();
|
||||
|
||||
boolean isXboxAchievementsEnabled();
|
||||
|
||||
int getCacheImages();
|
||||
|
||||
boolean isAllowCustomSkulls();
|
||||
|
||||
IMetricsInfo getMetrics();
|
||||
|
||||
interface IBedrockConfiguration {
|
||||
|
||||
String getAddress();
|
||||
|
||||
int getPort();
|
||||
|
||||
boolean isCloneRemotePort();
|
||||
|
||||
String getMotd1();
|
||||
|
||||
String getMotd2();
|
||||
|
||||
String getServerName();
|
||||
|
||||
int getCompressionLevel();
|
||||
|
||||
boolean isEnableProxyProtocol();
|
||||
|
||||
List<String> getProxyProtocolWhitelistedIPs();
|
||||
|
||||
/**
|
||||
* @return Unmodifiable list of {@link CIDRMatcher}s from {@link #getProxyProtocolWhitelistedIPs()}
|
||||
*/
|
||||
List<CIDRMatcher> getWhitelistedIPsMatchers();
|
||||
}
|
||||
|
||||
interface IRemoteConfiguration {
|
||||
|
||||
String getAddress();
|
||||
|
||||
int getPort();
|
||||
|
||||
void setAddress(String address);
|
||||
|
||||
void setPort(int port);
|
||||
|
||||
AuthType getAuthType();
|
||||
|
||||
boolean isPasswordAuthentication();
|
||||
|
||||
boolean isUseProxyProtocol();
|
||||
|
||||
boolean isForwardHost();
|
||||
}
|
||||
|
||||
interface IUserAuthenticationInfo {
|
||||
String getEmail();
|
||||
|
||||
String getPassword();
|
||||
|
||||
/**
|
||||
* Will be removed after Microsoft accounts are fully migrated
|
||||
*/
|
||||
@Deprecated
|
||||
boolean isMicrosoftAccount();
|
||||
}
|
||||
|
||||
interface IMetricsInfo {
|
||||
|
||||
boolean isEnabled();
|
||||
|
||||
String getUniqueId();
|
||||
}
|
||||
|
||||
int getScoreboardPacketThreshold();
|
||||
|
||||
// if u have offline mode enabled pls be safe
|
||||
boolean isEnableProxyConnections();
|
||||
|
||||
int getMtu();
|
||||
|
||||
boolean isUseDirectConnection();
|
||||
|
||||
int getConfigVersion();
|
||||
|
||||
static void checkGeyserConfiguration(GeyserConfiguration geyserConfig, GeyserLogger geyserLogger) {
|
||||
if (geyserConfig.getConfigVersion() < CURRENT_CONFIG_VERSION) {
|
||||
geyserLogger.warning(LanguageUtils.getLocaleStringLog("geyser.bootstrap.config.outdated"));
|
||||
} else if (geyserConfig.getConfigVersion() > CURRENT_CONFIG_VERSION) {
|
||||
geyserLogger.warning(LanguageUtils.getLocaleStringLog("geyser.bootstrap.config.too_new"));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,265 @@
|
|||
/*
|
||||
* Copyright (c) 2019-2021 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.configuration;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonIgnore;
|
||||
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
import com.fasterxml.jackson.core.JsonParser;
|
||||
import com.fasterxml.jackson.databind.DeserializationContext;
|
||||
import com.fasterxml.jackson.databind.JsonDeserializer;
|
||||
import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
import org.geysermc.connector.GeyserConnector;
|
||||
import org.geysermc.connector.common.AuthType;
|
||||
import org.geysermc.connector.common.serializer.AsteriskSerializer;
|
||||
import org.geysermc.connector.network.CIDRMatcher;
|
||||
import org.geysermc.connector.utils.LanguageUtils;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.nio.file.Path;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.UUID;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
@Getter
|
||||
@JsonIgnoreProperties(ignoreUnknown = true)
|
||||
@SuppressWarnings("FieldMayBeFinal") // Jackson requires that the fields are not final
|
||||
public abstract class GeyserJacksonConfiguration implements GeyserConfiguration {
|
||||
|
||||
/**
|
||||
* If the config was originally 'auto' before the values changed
|
||||
*/
|
||||
@Setter
|
||||
private boolean autoconfiguredRemote = false;
|
||||
|
||||
private BedrockConfiguration bedrock = new BedrockConfiguration();
|
||||
private RemoteConfiguration remote = new RemoteConfiguration();
|
||||
|
||||
@JsonProperty("floodgate-key-file")
|
||||
private String floodgateKeyFile = "key.pem";
|
||||
|
||||
public abstract Path getFloodgateKeyPath();
|
||||
|
||||
private Map<String, UserAuthenticationInfo> userAuths;
|
||||
|
||||
@JsonProperty("command-suggestions")
|
||||
private boolean commandSuggestions = true;
|
||||
|
||||
@JsonProperty("passthrough-motd")
|
||||
private boolean isPassthroughMotd = false;
|
||||
|
||||
@JsonProperty("passthrough-player-counts")
|
||||
private boolean isPassthroughPlayerCounts = false;
|
||||
|
||||
@JsonProperty("passthrough-protocol-name")
|
||||
private boolean isPassthroughProtocolName = false;
|
||||
|
||||
@JsonProperty("legacy-ping-passthrough")
|
||||
private boolean isLegacyPingPassthrough = false;
|
||||
|
||||
@JsonProperty("ping-passthrough-interval")
|
||||
private int pingPassthroughInterval = 3;
|
||||
|
||||
@JsonProperty("forward-player-ping")
|
||||
private boolean forwardPlayerPing = false;
|
||||
|
||||
@JsonProperty("max-players")
|
||||
private int maxPlayers = 100;
|
||||
|
||||
@JsonProperty("debug-mode")
|
||||
private boolean debugMode = false;
|
||||
|
||||
@JsonProperty("allow-third-party-capes")
|
||||
private boolean allowThirdPartyCapes = true;
|
||||
|
||||
@JsonProperty("show-cooldown")
|
||||
private String showCooldown = "title";
|
||||
|
||||
@JsonProperty("show-coordinates")
|
||||
private boolean showCoordinates = true;
|
||||
|
||||
@JsonDeserialize(using = EmoteOffhandWorkaroundOption.Deserializer.class)
|
||||
@JsonProperty("emote-offhand-workaround")
|
||||
private EmoteOffhandWorkaroundOption emoteOffhandWorkaround = EmoteOffhandWorkaroundOption.DISABLED;
|
||||
|
||||
@JsonProperty("allow-third-party-ears")
|
||||
private boolean allowThirdPartyEars = false;
|
||||
|
||||
@JsonProperty("default-locale")
|
||||
private String defaultLocale = null; // is null by default so system language takes priority
|
||||
|
||||
@JsonProperty("cache-images")
|
||||
private int cacheImages = 0;
|
||||
|
||||
@JsonProperty("allow-custom-skulls")
|
||||
private boolean allowCustomSkulls = true;
|
||||
|
||||
@JsonProperty("add-non-bedrock-items")
|
||||
private boolean addNonBedrockItems = true;
|
||||
|
||||
@JsonProperty("above-bedrock-nether-building")
|
||||
private boolean aboveBedrockNetherBuilding = false;
|
||||
|
||||
@JsonProperty("force-resource-packs")
|
||||
private boolean forceResourcePacks = true;
|
||||
|
||||
@JsonProperty("xbox-achievements-enabled")
|
||||
private boolean xboxAchievementsEnabled = false;
|
||||
|
||||
private MetricsInfo metrics = new MetricsInfo();
|
||||
|
||||
@Getter
|
||||
@JsonIgnoreProperties(ignoreUnknown = true)
|
||||
public static class BedrockConfiguration implements IBedrockConfiguration {
|
||||
@AsteriskSerializer.Asterisk(isIp = true)
|
||||
private String address = "0.0.0.0";
|
||||
|
||||
@Setter
|
||||
private int port = 19132;
|
||||
|
||||
@JsonProperty("clone-remote-port")
|
||||
private boolean cloneRemotePort = false;
|
||||
|
||||
private String motd1 = "GeyserMC";
|
||||
private String motd2 = "Geyser";
|
||||
|
||||
@JsonProperty("server-name")
|
||||
private String serverName = GeyserConnector.NAME;
|
||||
|
||||
@JsonProperty("compression-level")
|
||||
private int compressionLevel = 6;
|
||||
|
||||
public int getCompressionLevel() {
|
||||
return Math.max(-1, Math.min(compressionLevel, 9));
|
||||
}
|
||||
|
||||
@JsonProperty("enable-proxy-protocol")
|
||||
private boolean enableProxyProtocol = false;
|
||||
|
||||
@JsonProperty("proxy-protocol-whitelisted-ips")
|
||||
private List<String> proxyProtocolWhitelistedIPs = Collections.emptyList();
|
||||
|
||||
@JsonIgnore
|
||||
private List<CIDRMatcher> whitelistedIPsMatchers = null;
|
||||
|
||||
@Override
|
||||
public List<CIDRMatcher> getWhitelistedIPsMatchers() {
|
||||
// Effective Java, Third Edition; Item 83: Use lazy initialization judiciously
|
||||
List<CIDRMatcher> matchers = this.whitelistedIPsMatchers;
|
||||
if (matchers == null) {
|
||||
synchronized (this) {
|
||||
this.whitelistedIPsMatchers = matchers = proxyProtocolWhitelistedIPs.stream()
|
||||
.map(CIDRMatcher::new)
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
}
|
||||
return Collections.unmodifiableList(matchers);
|
||||
}
|
||||
}
|
||||
|
||||
@Getter
|
||||
@JsonIgnoreProperties(ignoreUnknown = true)
|
||||
public static class RemoteConfiguration implements IRemoteConfiguration {
|
||||
@Setter
|
||||
@AsteriskSerializer.Asterisk(isIp = true)
|
||||
private String address = "auto";
|
||||
|
||||
@JsonDeserialize(using = PortDeserializer.class)
|
||||
@Setter
|
||||
private int port = 25565;
|
||||
|
||||
@Setter
|
||||
@JsonDeserialize(using = AuthType.Deserializer.class)
|
||||
@JsonProperty("auth-type")
|
||||
private AuthType authType = AuthType.ONLINE;
|
||||
|
||||
@JsonProperty("allow-password-authentication")
|
||||
private boolean passwordAuthentication = true;
|
||||
|
||||
@JsonProperty("use-proxy-protocol")
|
||||
private boolean useProxyProtocol = false;
|
||||
|
||||
@JsonProperty("forward-hostname")
|
||||
private boolean forwardHost = false;
|
||||
}
|
||||
|
||||
@Getter
|
||||
@JsonIgnoreProperties(ignoreUnknown = true) // DO NOT REMOVE THIS! Otherwise, after we remove microsoft-account configs will not load
|
||||
public static class UserAuthenticationInfo implements IUserAuthenticationInfo {
|
||||
@AsteriskSerializer.Asterisk()
|
||||
private String email;
|
||||
|
||||
@AsteriskSerializer.Asterisk()
|
||||
private String password;
|
||||
|
||||
@JsonProperty("microsoft-account")
|
||||
private boolean microsoftAccount = false;
|
||||
}
|
||||
|
||||
@Getter
|
||||
@JsonIgnoreProperties(ignoreUnknown = true)
|
||||
public static class MetricsInfo implements IMetricsInfo {
|
||||
private boolean enabled = true;
|
||||
|
||||
@JsonProperty("uuid")
|
||||
private String uniqueId = UUID.randomUUID().toString();
|
||||
}
|
||||
|
||||
@JsonProperty("scoreboard-packet-threshold")
|
||||
private int scoreboardPacketThreshold = 10;
|
||||
|
||||
@JsonProperty("enable-proxy-connections")
|
||||
private boolean enableProxyConnections = false;
|
||||
|
||||
@JsonProperty("mtu")
|
||||
private int mtu = 1400;
|
||||
|
||||
@JsonProperty("use-direct-connection")
|
||||
private boolean useDirectConnection = true;
|
||||
|
||||
@JsonProperty("config-version")
|
||||
private int configVersion = 0;
|
||||
|
||||
/**
|
||||
* Ensure that the port deserializes in the config as a number no matter what.
|
||||
*/
|
||||
protected static class PortDeserializer extends JsonDeserializer<Integer> {
|
||||
@Override
|
||||
public Integer deserialize(JsonParser p, DeserializationContext ctxt) throws IOException {
|
||||
String value = p.getValueAsString();
|
||||
try {
|
||||
return Integer.parseInt(value);
|
||||
} catch (NumberFormatException e) {
|
||||
System.err.println(LanguageUtils.getLocaleStringLog("geyser.bootstrap.config.invalid_port"));
|
||||
return 25565;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,59 @@
|
|||
/*
|
||||
* Copyright (c) 2019-2021 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.dump;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Getter;
|
||||
import org.geysermc.common.PlatformType;
|
||||
import org.geysermc.connector.GeyserConnector;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@Getter
|
||||
public class BootstrapDumpInfo {
|
||||
private final PlatformType platform;
|
||||
|
||||
public BootstrapDumpInfo() {
|
||||
this.platform = GeyserConnector.getInstance().getPlatformType();
|
||||
}
|
||||
|
||||
@Getter
|
||||
@AllArgsConstructor
|
||||
public static class PluginInfo {
|
||||
public boolean enabled;
|
||||
public String name;
|
||||
public String version;
|
||||
public String main;
|
||||
public List<String> authors;
|
||||
}
|
||||
|
||||
@Getter
|
||||
@AllArgsConstructor
|
||||
public static class ListenerInfo {
|
||||
public String ip;
|
||||
public int port;
|
||||
}
|
||||
}
|
||||
259
core/src/main/java/org/geysermc/connector/dump/DumpInfo.java
Normal file
259
core/src/main/java/org/geysermc/connector/dump/DumpInfo.java
Normal file
|
|
@ -0,0 +1,259 @@
|
|||
/*
|
||||
* Copyright (c) 2019-2021 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.dump;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonIgnore;
|
||||
import com.fasterxml.jackson.databind.JsonNode;
|
||||
import com.google.common.hash.Hashing;
|
||||
import com.google.common.io.ByteSource;
|
||||
import com.google.common.io.Files;
|
||||
import com.nukkitx.protocol.bedrock.BedrockPacketCodec;
|
||||
import it.unimi.dsi.fastutil.objects.Object2IntMap;
|
||||
import it.unimi.dsi.fastutil.objects.Object2IntOpenHashMap;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Getter;
|
||||
import org.geysermc.connector.GeyserConnector;
|
||||
import org.geysermc.connector.common.serializer.AsteriskSerializer;
|
||||
import org.geysermc.connector.configuration.GeyserConfiguration;
|
||||
import org.geysermc.connector.network.MinecraftProtocol;
|
||||
import org.geysermc.connector.network.session.GeyserSession;
|
||||
import org.geysermc.connector.utils.DockerCheck;
|
||||
import org.geysermc.connector.utils.FileUtils;
|
||||
import org.geysermc.connector.utils.WebUtils;
|
||||
import org.geysermc.floodgate.util.DeviceOs;
|
||||
import org.geysermc.floodgate.util.FloodgateInfoHolder;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.lang.management.ManagementFactory;
|
||||
import java.net.InetAddress;
|
||||
import java.net.InetSocketAddress;
|
||||
import java.net.Socket;
|
||||
import java.net.UnknownHostException;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Properties;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
@Getter
|
||||
public class DumpInfo {
|
||||
@JsonIgnore
|
||||
private static final long MEGABYTE = 1024L * 1024L;
|
||||
|
||||
private final DumpInfo.VersionInfo versionInfo;
|
||||
private Properties gitInfo;
|
||||
private final GeyserConfiguration config;
|
||||
private final Floodgate floodgate;
|
||||
private final Object2IntMap<DeviceOs> userPlatforms;
|
||||
private final HashInfo hashInfo;
|
||||
private final RamInfo ramInfo;
|
||||
private LogsInfo logsInfo;
|
||||
private final BootstrapDumpInfo bootstrapInfo;
|
||||
private final FlagsInfo flagsInfo;
|
||||
|
||||
public DumpInfo(boolean addLog) {
|
||||
this.versionInfo = new VersionInfo();
|
||||
|
||||
try {
|
||||
this.gitInfo = new Properties();
|
||||
this.gitInfo.load(FileUtils.getResource("git.properties"));
|
||||
} catch (IOException ignored) {
|
||||
}
|
||||
|
||||
this.config = GeyserConnector.getInstance().getConfig();
|
||||
this.floodgate = new Floodgate();
|
||||
|
||||
String md5Hash = "unknown";
|
||||
String sha256Hash = "unknown";
|
||||
try {
|
||||
// https://stackoverflow.com/questions/320542/how-to-get-the-path-of-a-running-jar-file
|
||||
// https://stackoverflow.com/questions/304268/getting-a-files-md5-checksum-in-java
|
||||
File file = new File(DumpInfo.class.getProtectionDomain().getCodeSource().getLocation().toURI());
|
||||
ByteSource byteSource = Files.asByteSource(file);
|
||||
// Jenkins uses MD5 for its hash
|
||||
//noinspection UnstableApiUsage
|
||||
md5Hash = byteSource.hash(Hashing.md5()).toString();
|
||||
//noinspection UnstableApiUsage
|
||||
sha256Hash = byteSource.hash(Hashing.sha256()).toString();
|
||||
} catch (Exception e) {
|
||||
if (GeyserConnector.getInstance().getConfig().isDebugMode()) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
this.hashInfo = new HashInfo(md5Hash, sha256Hash);
|
||||
|
||||
this.ramInfo = new DumpInfo.RamInfo();
|
||||
|
||||
if (addLog) {
|
||||
this.logsInfo = new LogsInfo();
|
||||
}
|
||||
|
||||
this.userPlatforms = new Object2IntOpenHashMap<>();
|
||||
for (GeyserSession session : GeyserConnector.getInstance().getSessionManager().getAllSessions()) {
|
||||
DeviceOs device = session.getClientData().getDeviceOs();
|
||||
userPlatforms.put(device, userPlatforms.getOrDefault(device, 0) + 1);
|
||||
}
|
||||
|
||||
this.bootstrapInfo = GeyserConnector.getInstance().getBootstrap().getDumpInfo();
|
||||
|
||||
this.flagsInfo = new FlagsInfo();
|
||||
}
|
||||
|
||||
@Getter
|
||||
public static class VersionInfo {
|
||||
private final String name;
|
||||
private final String version;
|
||||
private final String javaName;
|
||||
private final String javaVendor;
|
||||
private final String javaVersion;
|
||||
private final String architecture;
|
||||
private final String operatingSystem;
|
||||
private final String operatingSystemVersion;
|
||||
|
||||
private final NetworkInfo network;
|
||||
private final MCInfo mcInfo;
|
||||
|
||||
VersionInfo() {
|
||||
this.name = GeyserConnector.NAME;
|
||||
this.version = GeyserConnector.VERSION;
|
||||
this.javaName = System.getProperty("java.vm.name");
|
||||
this.javaVendor = System.getProperty("java.vendor");
|
||||
this.javaVersion = ManagementFactory.getRuntimeMXBean().getVmVersion(); // Gives a little more to the version we can use over the system property
|
||||
// Usually gives Java architecture but still may be helpful.
|
||||
this.architecture = System.getProperty("os.arch");
|
||||
this.operatingSystem = System.getProperty("os.name");
|
||||
this.operatingSystemVersion = System.getProperty("os.version");
|
||||
|
||||
this.network = new NetworkInfo();
|
||||
this.mcInfo = new MCInfo();
|
||||
}
|
||||
}
|
||||
|
||||
@Getter
|
||||
public static class NetworkInfo {
|
||||
private final boolean dockerCheck;
|
||||
private String internalIP;
|
||||
|
||||
NetworkInfo() {
|
||||
if (AsteriskSerializer.showSensitive) {
|
||||
try {
|
||||
// This is the most reliable for getting the main local IP
|
||||
Socket socket = new Socket();
|
||||
socket.connect(new InetSocketAddress("geysermc.org", 80));
|
||||
this.internalIP = socket.getLocalAddress().getHostAddress();
|
||||
} catch (IOException e1) {
|
||||
try {
|
||||
// Fallback to the normal way of getting the local IP
|
||||
this.internalIP = InetAddress.getLocalHost().getHostAddress();
|
||||
} catch (UnknownHostException ignored) {
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// Sometimes the internal IP is the external IP...
|
||||
this.internalIP = "***";
|
||||
}
|
||||
|
||||
this.dockerCheck = DockerCheck.checkBasic();
|
||||
}
|
||||
}
|
||||
|
||||
@Getter
|
||||
public static class MCInfo {
|
||||
private final List<String> bedrockVersions;
|
||||
private final List<Integer> bedrockProtocols;
|
||||
private final int defaultBedrockProtocol;
|
||||
private final String javaVersion;
|
||||
private final int javaProtocol;
|
||||
|
||||
MCInfo() {
|
||||
this.bedrockVersions = MinecraftProtocol.SUPPORTED_BEDROCK_CODECS.stream().map(BedrockPacketCodec::getMinecraftVersion).toList();
|
||||
this.bedrockProtocols = MinecraftProtocol.SUPPORTED_BEDROCK_CODECS.stream().map(BedrockPacketCodec::getProtocolVersion).toList();
|
||||
this.defaultBedrockProtocol = MinecraftProtocol.DEFAULT_BEDROCK_CODEC.getProtocolVersion();
|
||||
this.javaVersion = MinecraftProtocol.getJavaVersion();
|
||||
this.javaProtocol = MinecraftProtocol.getJavaProtocolVersion();
|
||||
}
|
||||
}
|
||||
|
||||
@Getter
|
||||
public static class Floodgate {
|
||||
private final Properties gitInfo;
|
||||
private final Object config;
|
||||
|
||||
Floodgate() {
|
||||
this.gitInfo = FloodgateInfoHolder.getGitProperties();
|
||||
this.config = FloodgateInfoHolder.getConfig();
|
||||
}
|
||||
}
|
||||
|
||||
@Getter
|
||||
public static class LogsInfo {
|
||||
private String link;
|
||||
|
||||
public LogsInfo() {
|
||||
try {
|
||||
Map<String, String> fields = new HashMap<>();
|
||||
fields.put("content", FileUtils.readAllLines(GeyserConnector.getInstance().getBootstrap().getLogsPath()).collect(Collectors.joining("\n")));
|
||||
|
||||
JsonNode logData = GeyserConnector.JSON_MAPPER.readTree(WebUtils.postForm("https://api.mclo.gs/1/log", fields));
|
||||
|
||||
this.link = logData.get("url").textValue();
|
||||
} catch (IOException ignored) { }
|
||||
}
|
||||
}
|
||||
|
||||
@AllArgsConstructor
|
||||
@Getter
|
||||
public static class HashInfo {
|
||||
private final String md5Hash;
|
||||
private final String sha256Hash;
|
||||
}
|
||||
|
||||
@Getter
|
||||
public static class RamInfo {
|
||||
private final long free;
|
||||
private final long total;
|
||||
private final long max;
|
||||
|
||||
RamInfo() {
|
||||
this.free = Runtime.getRuntime().freeMemory() / MEGABYTE;
|
||||
this.total = Runtime.getRuntime().totalMemory() / MEGABYTE;
|
||||
this.max = Runtime.getRuntime().maxMemory() / MEGABYTE;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* E.G. `-Xmx1024M` - all runtime JVM flags on this machine
|
||||
*/
|
||||
@Getter
|
||||
public static class FlagsInfo {
|
||||
private final List<String> flags;
|
||||
|
||||
FlagsInfo() {
|
||||
this.flags = ManagementFactory.getRuntimeMXBean().getInputArguments();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,76 @@
|
|||
/*
|
||||
* Copyright (c) 2019-2021 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.type.ByteEntityMetadata;
|
||||
import com.github.steveice10.mc.protocol.data.game.entity.type.EntityType;
|
||||
import com.nukkitx.math.vector.Vector3f;
|
||||
import com.nukkitx.protocol.bedrock.data.entity.EntityFlag;
|
||||
import org.geysermc.connector.network.session.GeyserSession;
|
||||
|
||||
import java.util.UUID;
|
||||
|
||||
public class AbstractArrowEntity extends Entity {
|
||||
|
||||
public AbstractArrowEntity(GeyserSession session, long entityId, long geyserId, UUID uuid, EntityDefinition<?> definition, Vector3f position, Vector3f motion, float yaw, float pitch, float headYaw) {
|
||||
super(session, entityId, geyserId, uuid, definition, position, motion, yaw, pitch, headYaw);
|
||||
|
||||
// Set the correct texture if using the resource pack
|
||||
setFlag(EntityFlag.BRIBED, definition.entityType() == EntityType.SPECTRAL_ARROW);
|
||||
|
||||
setMotion(motion);
|
||||
}
|
||||
|
||||
public void setArrowFlags(ByteEntityMetadata entityMetadata) {
|
||||
byte data = entityMetadata.getPrimitiveValue();
|
||||
|
||||
setFlag(EntityFlag.CRITICAL, (data & 0x01) == 0x01);
|
||||
}
|
||||
|
||||
// Ignore the rotation sent by the Java server since the
|
||||
// Java client calculates the rotation from the motion
|
||||
@Override
|
||||
public void setYaw(float yaw) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setPitch(float pitch) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setHeadYaw(float headYaw) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setMotion(Vector3f motion) {
|
||||
super.setMotion(motion);
|
||||
|
||||
double horizontalSpeed = Math.sqrt(motion.getX() * motion.getX() + motion.getZ() * motion.getZ());
|
||||
this.yaw = (float) Math.toDegrees(Math.atan2(motion.getX(), motion.getZ()));
|
||||
this.pitch = (float) Math.toDegrees(Math.atan2(motion.getY(), horizontalSpeed));
|
||||
this.headYaw = yaw;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,72 @@
|
|||
/*
|
||||
* Copyright (c) 2019-2021 GeyserMC. http://geysermc.org
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*
|
||||
* @author GeyserMC
|
||||
* @link https://github.com/GeyserMC/Geyser
|
||||
*/
|
||||
|
||||
package org.geysermc.connector.entity;
|
||||
|
||||
import com.github.steveice10.mc.protocol.data.game.entity.metadata.EntityMetadata;
|
||||
import com.github.steveice10.mc.protocol.data.game.entity.metadata.type.FloatEntityMetadata;
|
||||
import com.github.steveice10.mc.protocol.data.game.level.particle.Particle;
|
||||
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.network.session.GeyserSession;
|
||||
import org.geysermc.connector.utils.EffectUtils;
|
||||
|
||||
import java.util.UUID;
|
||||
|
||||
public class AreaEffectCloudEntity extends Entity {
|
||||
|
||||
public AreaEffectCloudEntity(GeyserSession session, long entityId, long geyserId, UUID uuid, EntityDefinition<?> definition, Vector3f position, Vector3f motion, float yaw, float pitch, float headYaw) {
|
||||
super(session, entityId, geyserId, uuid, definition, position, motion, yaw, pitch, headYaw);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void initializeMetadata() {
|
||||
super.initializeMetadata();
|
||||
// Without this the cloud doesn't appear,
|
||||
dirtyMetadata.put(EntityData.AREA_EFFECT_CLOUD_DURATION, 600);
|
||||
|
||||
// This disabled client side shrink of the cloud
|
||||
dirtyMetadata.put(EntityData.AREA_EFFECT_CLOUD_RADIUS, 0.0f);
|
||||
dirtyMetadata.put(EntityData.AREA_EFFECT_CLOUD_CHANGE_RATE, -0.005f);
|
||||
dirtyMetadata.put(EntityData.AREA_EFFECT_CLOUD_CHANGE_ON_PICKUP, -0.5f);
|
||||
|
||||
setFlag(EntityFlag.FIRE_IMMUNE, true);
|
||||
}
|
||||
|
||||
public void setRadius(FloatEntityMetadata entityMetadata) {
|
||||
float value = entityMetadata.getPrimitiveValue();
|
||||
dirtyMetadata.put(EntityData.AREA_EFFECT_CLOUD_RADIUS, value);
|
||||
dirtyMetadata.put(EntityData.BOUNDING_BOX_WIDTH, 2.0f * value);
|
||||
}
|
||||
|
||||
public void setParticle(EntityMetadata<Particle, ?> entityMetadata) {
|
||||
Particle particle = entityMetadata.getValue();
|
||||
int particleId = EffectUtils.getParticleId(session, particle.getType());
|
||||
if (particleId != -1) {
|
||||
dirtyMetadata.put(EntityData.AREA_EFFECT_CLOUD_PARTICLE_ID, particleId);
|
||||
}
|
||||
}
|
||||
}
|
||||
188
core/src/main/java/org/geysermc/connector/entity/BoatEntity.java
Normal file
188
core/src/main/java/org/geysermc/connector/entity/BoatEntity.java
Normal file
|
|
@ -0,0 +1,188 @@
|
|||
/*
|
||||
* Copyright (c) 2019-2021 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.type.BooleanEntityMetadata;
|
||||
import com.github.steveice10.mc.protocol.data.game.entity.metadata.type.IntEntityMetadata;
|
||||
import com.nukkitx.math.vector.Vector3f;
|
||||
import com.nukkitx.protocol.bedrock.data.entity.EntityData;
|
||||
import com.nukkitx.protocol.bedrock.packet.AnimatePacket;
|
||||
import com.nukkitx.protocol.bedrock.packet.MoveEntityAbsolutePacket;
|
||||
import lombok.Getter;
|
||||
import org.geysermc.connector.network.session.GeyserSession;
|
||||
|
||||
import java.util.UUID;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
public class BoatEntity extends Entity {
|
||||
|
||||
/**
|
||||
* Required when IS_BUOYANT is sent in order for boats to work in the water. <br>
|
||||
*
|
||||
* Taken from BDS 1.16.200, with the modification of <code>simulate_waves</code> since Java doesn't bob the boat up and down
|
||||
* like Bedrock.
|
||||
*/
|
||||
private static final String BUOYANCY_DATA = "{\"apply_gravity\":true,\"base_buoyancy\":1.0,\"big_wave_probability\":0.02999999932944775," +
|
||||
"\"big_wave_speed\":10.0,\"drag_down_on_buoyancy_removed\":0.0,\"liquid_blocks\":[\"minecraft:water\"," +
|
||||
"\"minecraft:flowing_water\"],\"simulate_waves\":false}";
|
||||
|
||||
private boolean isPaddlingLeft;
|
||||
private float paddleTimeLeft;
|
||||
private boolean isPaddlingRight;
|
||||
private float paddleTimeRight;
|
||||
|
||||
/**
|
||||
* Saved for using the "pick" functionality on a boat.
|
||||
*/
|
||||
@Getter
|
||||
private int variant;
|
||||
|
||||
// Looks too fast and too choppy with 0.1f, which is how I believe the Microsoftian client handles it
|
||||
private final float ROWING_SPEED = 0.05f;
|
||||
|
||||
public BoatEntity(GeyserSession session, long entityId, long geyserId, UUID uuid, EntityDefinition<?> definition, Vector3f position, Vector3f motion, float yaw, float pitch, float headYaw) {
|
||||
// Initial rotation is incorrect
|
||||
super(session, entityId, geyserId, uuid, definition, position.add(0d, definition.offset(), 0d), motion, yaw + 90, 0, yaw + 90);
|
||||
|
||||
// Required to be able to move on land 1.16.200+ or apply gravity not in the water 1.16.100+
|
||||
dirtyMetadata.put(EntityData.IS_BUOYANT, (byte) 1);
|
||||
dirtyMetadata.put(EntityData.BUOYANCY_DATA, BUOYANCY_DATA);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void moveAbsolute(Vector3f position, float yaw, float pitch, float headYaw, boolean isOnGround, boolean teleported) {
|
||||
// We don't include the rotation (y) as it causes the boat to appear sideways
|
||||
setPosition(position.add(0d, this.definition.offset(), 0d));
|
||||
this.yaw = yaw + 90;
|
||||
this.headYaw = yaw + 90;
|
||||
setOnGround(isOnGround);
|
||||
|
||||
MoveEntityAbsolutePacket moveEntityPacket = new MoveEntityAbsolutePacket();
|
||||
moveEntityPacket.setRuntimeEntityId(geyserId);
|
||||
// Minimal glitching when ClientboundMoveVehiclePacket is sent
|
||||
moveEntityPacket.setPosition(session.getRidingVehicleEntity() == this ? position.up(EntityDefinitions.PLAYER.offset() - this.definition.offset()) : this.position);
|
||||
moveEntityPacket.setRotation(getBedrockRotation());
|
||||
moveEntityPacket.setOnGround(isOnGround);
|
||||
moveEntityPacket.setTeleported(teleported);
|
||||
|
||||
session.sendUpstreamPacket(moveEntityPacket);
|
||||
}
|
||||
|
||||
/**
|
||||
* Move the boat without making the adjustments needed to translate from Java
|
||||
*/
|
||||
public void moveAbsoluteWithoutAdjustments(Vector3f position, float yaw, boolean isOnGround, boolean teleported) {
|
||||
super.moveAbsolute(position, yaw, 0, yaw, isOnGround, teleported);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void moveRelative(double relX, double relY, double relZ, float yaw, float pitch, float headYaw, boolean isOnGround) {
|
||||
super.moveRelative(relX, relY, relZ, yaw, 0, yaw, isOnGround);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updatePositionAndRotation(double moveX, double moveY, double moveZ, float yaw, float pitch, boolean isOnGround) {
|
||||
moveRelative(moveX, moveY, moveZ, yaw + 90, pitch, isOnGround);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateRotation(float yaw, float pitch, boolean isOnGround) {
|
||||
moveRelative(0, 0, 0, yaw + 90, 0, 0, isOnGround);
|
||||
}
|
||||
|
||||
public void setVariant(IntEntityMetadata entityMetadata) {
|
||||
variant = entityMetadata.getPrimitiveValue();
|
||||
dirtyMetadata.put(EntityData.VARIANT, variant);
|
||||
}
|
||||
|
||||
public void setPaddlingLeft(BooleanEntityMetadata entityMetadata) {
|
||||
isPaddlingLeft = entityMetadata.getPrimitiveValue();
|
||||
if (isPaddlingLeft) {
|
||||
// Java sends simply "true" and "false" (is_paddling_left), Bedrock keeps sending packets as you're rowing
|
||||
// This is an asynchronous method that emulates Bedrock rowing until "false" is sent.
|
||||
paddleTimeLeft = 0f;
|
||||
if (!this.passengers.isEmpty()) {
|
||||
// Get the entity by the first stored passenger and convey motion in this manner
|
||||
Entity entity = session.getEntityCache().getEntityByJavaId(this.passengers.iterator().nextLong());
|
||||
if (entity != null) {
|
||||
updateLeftPaddle(session, entity);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// Indicate that the row position should be reset
|
||||
dirtyMetadata.put(EntityData.ROW_TIME_LEFT, 0.0f);
|
||||
}
|
||||
}
|
||||
|
||||
public void setPaddlingRight(BooleanEntityMetadata entityMetadata) {
|
||||
isPaddlingRight = entityMetadata.getPrimitiveValue();
|
||||
if (isPaddlingRight) {
|
||||
paddleTimeRight = 0f;
|
||||
if (!this.passengers.isEmpty()) {
|
||||
Entity entity = session.getEntityCache().getEntityByJavaId(this.passengers.iterator().nextLong());
|
||||
if (entity != null) {
|
||||
updateRightPaddle(session, entity);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
dirtyMetadata.put(EntityData.ROW_TIME_RIGHT, 0.0f);
|
||||
}
|
||||
}
|
||||
|
||||
private void updateLeftPaddle(GeyserSession session, Entity rower) {
|
||||
if (isPaddlingLeft) {
|
||||
paddleTimeLeft += ROWING_SPEED;
|
||||
sendAnimationPacket(session, rower, AnimatePacket.Action.ROW_LEFT, paddleTimeLeft);
|
||||
|
||||
session.scheduleInEventLoop(() ->
|
||||
updateLeftPaddle(session, rower),
|
||||
100,
|
||||
TimeUnit.MILLISECONDS
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
private void updateRightPaddle(GeyserSession session, Entity rower) {
|
||||
if (isPaddlingRight) {
|
||||
paddleTimeRight += ROWING_SPEED;
|
||||
sendAnimationPacket(session, rower, AnimatePacket.Action.ROW_RIGHT, paddleTimeRight);
|
||||
|
||||
session.scheduleInEventLoop(() ->
|
||||
updateRightPaddle(session, rower),
|
||||
100,
|
||||
TimeUnit.MILLISECONDS
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
private void sendAnimationPacket(GeyserSession session, Entity rower, AnimatePacket.Action action, float rowTime) {
|
||||
AnimatePacket packet = new AnimatePacket();
|
||||
packet.setRuntimeEntityId(rower.getGeyserId());
|
||||
packet.setAction(action);
|
||||
packet.setRowingTime(rowTime);
|
||||
session.sendUpstreamPacket(packet);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,57 @@
|
|||
/*
|
||||
* Copyright (c) 2019-2021 GeyserMC. http://geysermc.org
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*
|
||||
* @author GeyserMC
|
||||
* @link https://github.com/GeyserMC/Geyser
|
||||
*/
|
||||
|
||||
package org.geysermc.connector.entity;
|
||||
|
||||
import com.nukkitx.math.vector.Vector3f;
|
||||
import com.nukkitx.protocol.bedrock.data.entity.EntityData;
|
||||
import org.geysermc.connector.network.session.GeyserSession;
|
||||
|
||||
import java.util.UUID;
|
||||
|
||||
public class CommandBlockMinecartEntity extends DefaultBlockMinecartEntity {
|
||||
|
||||
public CommandBlockMinecartEntity(GeyserSession session, long entityId, long geyserId, UUID uuid, EntityDefinition<?> definition, Vector3f position, Vector3f motion, float yaw, float pitch, float headYaw) {
|
||||
super(session, entityId, geyserId, uuid, definition, position, motion, yaw, pitch, headYaw);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void initializeMetadata() {
|
||||
// Required, or else the GUI will not open
|
||||
dirtyMetadata.put(EntityData.CONTAINER_TYPE, (byte) 16);
|
||||
dirtyMetadata.put(EntityData.CONTAINER_BASE_SIZE, 1);
|
||||
// Required, or else the client does not bother to send a packet back with the new information
|
||||
dirtyMetadata.put(EntityData.COMMAND_BLOCK_ENABLED, (byte) 1);
|
||||
}
|
||||
|
||||
/**
|
||||
* By default, the command block shown is purple on Bedrock, which does not match Java Edition's orange.
|
||||
*/
|
||||
@Override
|
||||
public void updateDefaultBlockMetadata() {
|
||||
dirtyMetadata.put(EntityData.DISPLAY_ITEM, session.getBlockMappings().getCommandBlockRuntimeId());
|
||||
dirtyMetadata.put(EntityData.DISPLAY_OFFSET, 6);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,89 @@
|
|||
/*
|
||||
* Copyright (c) 2019-2021 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.type.BooleanEntityMetadata;
|
||||
import com.github.steveice10.mc.protocol.data.game.entity.metadata.type.IntEntityMetadata;
|
||||
import com.nukkitx.math.vector.Vector3f;
|
||||
import com.nukkitx.protocol.bedrock.data.entity.EntityData;
|
||||
import org.geysermc.connector.network.session.GeyserSession;
|
||||
|
||||
import java.util.UUID;
|
||||
|
||||
/**
|
||||
* This class is used as a base for minecarts with a default block to display like furnaces and spawners
|
||||
*/
|
||||
public class DefaultBlockMinecartEntity extends MinecartEntity {
|
||||
|
||||
public int customBlock = 0;
|
||||
public int customBlockOffset = 0;
|
||||
public boolean showCustomBlock = false;
|
||||
|
||||
public DefaultBlockMinecartEntity(GeyserSession session, long entityId, long geyserId, UUID uuid, EntityDefinition<?> definition, Vector3f position, Vector3f motion, float yaw, float pitch, float headYaw) {
|
||||
super(session, entityId, geyserId, uuid, definition, position, motion, yaw, pitch, headYaw);
|
||||
|
||||
dirtyMetadata.put(EntityData.CUSTOM_DISPLAY, (byte) 1);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void spawnEntity() {
|
||||
updateDefaultBlockMetadata();
|
||||
super.spawnEntity();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setCustomBlock(IntEntityMetadata entityMetadata) {
|
||||
customBlock = ((IntEntityMetadata) entityMetadata).getPrimitiveValue();
|
||||
|
||||
if (showCustomBlock) {
|
||||
dirtyMetadata.put(EntityData.DISPLAY_ITEM, session.getBlockMappings().getBedrockBlockId(customBlock));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setCustomBlockOffset(IntEntityMetadata entityMetadata) {
|
||||
customBlockOffset = entityMetadata.getPrimitiveValue();
|
||||
|
||||
if (showCustomBlock) {
|
||||
dirtyMetadata.put(EntityData.DISPLAY_OFFSET, customBlockOffset);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setShowCustomBlock(BooleanEntityMetadata entityMetadata) {
|
||||
if (entityMetadata.getPrimitiveValue()) {
|
||||
showCustomBlock = true;
|
||||
dirtyMetadata.put(EntityData.DISPLAY_ITEM, session.getBlockMappings().getBedrockBlockId(customBlock));
|
||||
dirtyMetadata.put(EntityData.DISPLAY_OFFSET, customBlockOffset);
|
||||
} else {
|
||||
showCustomBlock = false;
|
||||
updateDefaultBlockMetadata();
|
||||
}
|
||||
}
|
||||
|
||||
public void updateDefaultBlockMetadata() {
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,63 @@
|
|||
/*
|
||||
* Copyright (c) 2019-2021 GeyserMC. http://geysermc.org
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*
|
||||
* @author GeyserMC
|
||||
* @link https://github.com/GeyserMC/Geyser
|
||||
*/
|
||||
|
||||
package org.geysermc.connector.entity;
|
||||
|
||||
import com.github.steveice10.mc.protocol.data.game.entity.metadata.EntityMetadata;
|
||||
import com.github.steveice10.mc.protocol.data.game.entity.metadata.Position;
|
||||
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 org.geysermc.connector.network.session.GeyserSession;
|
||||
|
||||
import java.util.Optional;
|
||||
import java.util.UUID;
|
||||
|
||||
public class EnderCrystalEntity extends Entity {
|
||||
|
||||
public EnderCrystalEntity(GeyserSession session, long entityId, long geyserId, UUID uuid, EntityDefinition<?> definition, Vector3f position, Vector3f motion, float yaw, float pitch, float headYaw) {
|
||||
super(session, entityId, geyserId, uuid, definition, position, motion, yaw, pitch, headYaw);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void initializeMetadata() {
|
||||
super.initializeMetadata();
|
||||
// Bedrock 1.16.100+ - prevents the entity from appearing on fire itself when fire is underneath it
|
||||
setFlag(EntityFlag.FIRE_IMMUNE, true);
|
||||
}
|
||||
|
||||
public void setBlockTarget(EntityMetadata<Optional<Position>, ?> entityMetadata) {
|
||||
// Show beam
|
||||
// Usually performed client-side on Bedrock except for Ender Dragon respawn event
|
||||
Optional<Position> optionalPos = entityMetadata.getValue();
|
||||
if (optionalPos.isPresent()) {
|
||||
Position pos = optionalPos.get();
|
||||
dirtyMetadata.put(EntityData.BLOCK_TARGET, Vector3i.from(pos.getX(), pos.getY(), pos.getZ()));
|
||||
} else {
|
||||
dirtyMetadata.put(EntityData.BLOCK_TARGET, Vector3i.ZERO);
|
||||
}
|
||||
}
|
||||
}
|
||||
439
core/src/main/java/org/geysermc/connector/entity/Entity.java
Normal file
439
core/src/main/java/org/geysermc/connector/entity/Entity.java
Normal file
|
|
@ -0,0 +1,439 @@
|
|||
/*
|
||||
* Copyright (c) 2019-2021 GeyserMC. http://geysermc.org
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*
|
||||
* @author GeyserMC
|
||||
* @link https://github.com/GeyserMC/Geyser
|
||||
*/
|
||||
|
||||
package org.geysermc.connector.entity;
|
||||
|
||||
import com.github.steveice10.mc.protocol.data.game.entity.metadata.EntityMetadata;
|
||||
import com.github.steveice10.mc.protocol.data.game.entity.metadata.Pose;
|
||||
import com.github.steveice10.mc.protocol.data.game.entity.metadata.type.BooleanEntityMetadata;
|
||||
import com.github.steveice10.mc.protocol.data.game.entity.metadata.type.ByteEntityMetadata;
|
||||
import com.github.steveice10.mc.protocol.data.game.entity.metadata.type.IntEntityMetadata;
|
||||
import com.nukkitx.math.vector.Vector3f;
|
||||
import com.nukkitx.protocol.bedrock.data.entity.EntityData;
|
||||
import com.nukkitx.protocol.bedrock.data.entity.EntityFlag;
|
||||
import com.nukkitx.protocol.bedrock.data.entity.EntityFlags;
|
||||
import com.nukkitx.protocol.bedrock.packet.AddEntityPacket;
|
||||
import com.nukkitx.protocol.bedrock.packet.MoveEntityAbsolutePacket;
|
||||
import com.nukkitx.protocol.bedrock.packet.RemoveEntityPacket;
|
||||
import com.nukkitx.protocol.bedrock.packet.SetEntityDataPacket;
|
||||
import it.unimi.dsi.fastutil.longs.LongOpenHashSet;
|
||||
import lombok.AccessLevel;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
import net.kyori.adventure.text.Component;
|
||||
import org.geysermc.connector.network.session.GeyserSession;
|
||||
import org.geysermc.connector.network.translators.chat.MessageTranslator;
|
||||
import org.geysermc.connector.utils.MathUtils;
|
||||
|
||||
import java.util.Optional;
|
||||
import java.util.UUID;
|
||||
|
||||
@Getter
|
||||
@Setter
|
||||
public class Entity {
|
||||
protected final GeyserSession session;
|
||||
|
||||
protected long entityId;
|
||||
protected final long geyserId;
|
||||
protected UUID uuid;
|
||||
|
||||
protected Vector3f position;
|
||||
protected Vector3f motion;
|
||||
|
||||
/**
|
||||
* x = Yaw, y = Pitch, z = HeadYaw
|
||||
*/
|
||||
protected float yaw;
|
||||
protected float pitch;
|
||||
protected float headYaw;
|
||||
|
||||
/**
|
||||
* Saves if the entity should be on the ground. Otherwise entities like parrots are flapping when rotating
|
||||
*/
|
||||
protected boolean onGround;
|
||||
|
||||
protected EntityDefinition<?> definition;
|
||||
|
||||
protected boolean valid;
|
||||
|
||||
/* Metadata about this specific entity */
|
||||
@Setter(AccessLevel.NONE)
|
||||
protected float boundingBoxHeight;
|
||||
@Setter(AccessLevel.NONE)
|
||||
protected float boundingBoxWidth;
|
||||
@Setter(AccessLevel.NONE)
|
||||
protected String nametag = "";
|
||||
/* Metadata end */
|
||||
|
||||
protected LongOpenHashSet passengers = new LongOpenHashSet();
|
||||
/**
|
||||
* A container to store temporary metadata before it's sent to Bedrock.
|
||||
*/
|
||||
protected final GeyserDirtyMetadata dirtyMetadata = new GeyserDirtyMetadata();
|
||||
/**
|
||||
* The entity flags for the Bedrock entity.
|
||||
* These must always be saved - if flags are updated and the other values aren't present, the Bedrock client will
|
||||
* think they are set to false.
|
||||
*/
|
||||
@Getter(AccessLevel.NONE)
|
||||
protected final EntityFlags flags = new EntityFlags();
|
||||
/**
|
||||
* Indicates if flags have been updated and need to be sent to the client.
|
||||
*/
|
||||
@Getter(AccessLevel.NONE)
|
||||
@Setter(AccessLevel.PROTECTED) // For players
|
||||
private boolean flagsDirty = false;
|
||||
|
||||
public Entity(GeyserSession session, long entityId, long geyserId, UUID uuid, EntityDefinition<?> definition, Vector3f position, Vector3f motion, float yaw, float pitch, float headYaw) {
|
||||
this.session = session;
|
||||
|
||||
this.entityId = entityId;
|
||||
this.geyserId = geyserId;
|
||||
this.uuid = uuid;
|
||||
this.definition = definition;
|
||||
this.motion = motion;
|
||||
this.yaw = yaw;
|
||||
this.pitch = pitch;
|
||||
this.headYaw = headYaw;
|
||||
|
||||
this.valid = false;
|
||||
|
||||
setPosition(position);
|
||||
setAirSupply(getMaxAir());
|
||||
|
||||
initializeMetadata();
|
||||
}
|
||||
|
||||
/**
|
||||
* Called on entity spawn. Used to populate the entity metadata and flags with default values.
|
||||
*/
|
||||
protected void initializeMetadata() {
|
||||
dirtyMetadata.put(EntityData.SCALE, 1f);
|
||||
dirtyMetadata.put(EntityData.COLOR, 0);
|
||||
dirtyMetadata.put(EntityData.MAX_AIR_SUPPLY, getMaxAir());
|
||||
setDimensions(Pose.STANDING);
|
||||
setFlag(EntityFlag.HAS_GRAVITY, true);
|
||||
setFlag(EntityFlag.HAS_COLLISION, true);
|
||||
setFlag(EntityFlag.CAN_SHOW_NAME, true);
|
||||
setFlag(EntityFlag.CAN_CLIMB, true);
|
||||
}
|
||||
|
||||
public void spawnEntity() {
|
||||
AddEntityPacket addEntityPacket = new AddEntityPacket();
|
||||
addEntityPacket.setIdentifier(definition.identifier());
|
||||
addEntityPacket.setRuntimeEntityId(geyserId);
|
||||
addEntityPacket.setUniqueEntityId(geyserId);
|
||||
addEntityPacket.setPosition(position);
|
||||
addEntityPacket.setMotion(motion);
|
||||
addEntityPacket.setRotation(getBedrockRotation());
|
||||
addEntityPacket.getMetadata().putFlags(flags);
|
||||
dirtyMetadata.apply(addEntityPacket.getMetadata());
|
||||
addAdditionalSpawnData(addEntityPacket);
|
||||
|
||||
valid = true;
|
||||
session.sendUpstreamPacket(addEntityPacket);
|
||||
|
||||
flagsDirty = false;
|
||||
|
||||
session.getConnector().getLogger().debug("Spawned entity " + getClass().getName() + " at location " + position + " with id " + geyserId + " (java id " + entityId + ")");
|
||||
}
|
||||
|
||||
/**
|
||||
* To be overridden in other entity classes, if additional things need to be done to the spawn entity packet.
|
||||
*/
|
||||
public void addAdditionalSpawnData(AddEntityPacket addEntityPacket) {
|
||||
}
|
||||
|
||||
/**
|
||||
* Despawns the entity
|
||||
*
|
||||
* @return can be deleted
|
||||
*/
|
||||
public boolean despawnEntity() {
|
||||
if (!valid) return true;
|
||||
|
||||
for (long passenger : passengers) { // Make sure all passengers on the despawned entity are updated
|
||||
Entity entity = session.getEntityCache().getEntityByJavaId(passenger);
|
||||
if (entity == null) continue;
|
||||
entity.setFlag(EntityFlag.RIDING, false);
|
||||
entity.updateBedrockMetadata();
|
||||
}
|
||||
|
||||
RemoveEntityPacket removeEntityPacket = new RemoveEntityPacket();
|
||||
removeEntityPacket.setUniqueEntityId(geyserId);
|
||||
session.sendUpstreamPacket(removeEntityPacket);
|
||||
|
||||
valid = false;
|
||||
return true;
|
||||
}
|
||||
|
||||
public void moveRelative(double relX, double relY, double relZ, float yaw, float pitch, boolean isOnGround) {
|
||||
moveRelative(relX, relY, relZ, yaw, pitch, this.headYaw, isOnGround);
|
||||
}
|
||||
|
||||
public void moveRelative(double relX, double relY, double relZ, float yaw, float pitch, float headYaw, boolean isOnGround) {
|
||||
setYaw(yaw);
|
||||
setPitch(pitch);
|
||||
setHeadYaw(headYaw);
|
||||
setOnGround(isOnGround);
|
||||
this.position = Vector3f.from(position.getX() + relX, position.getY() + relY, position.getZ() + relZ);
|
||||
|
||||
MoveEntityAbsolutePacket moveEntityPacket = new MoveEntityAbsolutePacket();
|
||||
moveEntityPacket.setRuntimeEntityId(geyserId);
|
||||
moveEntityPacket.setPosition(position);
|
||||
moveEntityPacket.setRotation(getBedrockRotation());
|
||||
moveEntityPacket.setOnGround(isOnGround);
|
||||
moveEntityPacket.setTeleported(false);
|
||||
|
||||
session.sendUpstreamPacket(moveEntityPacket);
|
||||
}
|
||||
|
||||
public void moveAbsolute(Vector3f position, float yaw, float pitch, boolean isOnGround, boolean teleported) {
|
||||
moveAbsolute(position, yaw, pitch, this.headYaw, isOnGround, teleported);
|
||||
}
|
||||
|
||||
public void moveAbsolute(Vector3f position, float yaw, float pitch, float headYaw, boolean isOnGround, boolean teleported) {
|
||||
setPosition(position);
|
||||
// Setters are intentional so it can be overridden in places like AbstractArrowEntity
|
||||
setYaw(yaw);
|
||||
setPitch(pitch);
|
||||
setHeadYaw(headYaw);
|
||||
setOnGround(isOnGround);
|
||||
|
||||
MoveEntityAbsolutePacket moveEntityPacket = new MoveEntityAbsolutePacket();
|
||||
moveEntityPacket.setRuntimeEntityId(geyserId);
|
||||
moveEntityPacket.setPosition(position);
|
||||
moveEntityPacket.setRotation(getBedrockRotation());
|
||||
moveEntityPacket.setOnGround(isOnGround);
|
||||
moveEntityPacket.setTeleported(teleported);
|
||||
|
||||
session.sendUpstreamPacket(moveEntityPacket);
|
||||
}
|
||||
|
||||
/**
|
||||
* Teleports an entity to a new location. Used in JavaTeleportEntityTranslator.
|
||||
* @param position The new position of the entity.
|
||||
* @param yaw The new yaw of the entity.
|
||||
* @param pitch The new pitch of the entity.
|
||||
* @param isOnGround Whether the entity is currently on the ground.
|
||||
*/
|
||||
public void teleport(Vector3f position, float yaw, float pitch, boolean isOnGround) {
|
||||
moveAbsolute(position, yaw, pitch, isOnGround, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates an entity's head position. Used in JavaRotateHeadTranslator.
|
||||
* @param headYaw The new head rotation of the entity.
|
||||
*/
|
||||
public void updateHeadLookRotation(float headYaw) {
|
||||
moveRelative(0, 0, 0, headYaw, pitch, this.headYaw, onGround);
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates an entity's position and rotation. Used in JavaMoveEntityPosRotTranslator.
|
||||
* @param moveX The new X offset of the current position.
|
||||
* @param moveY The new Y offset of the current position.
|
||||
* @param moveZ The new Z offset of the current position.
|
||||
* @param yaw The new yaw of the entity.
|
||||
* @param pitch The new pitch of the entity.
|
||||
* @param isOnGround Whether the entity is currently on the ground.
|
||||
*/
|
||||
public void updatePositionAndRotation(double moveX, double moveY, double moveZ, float yaw, float pitch, boolean isOnGround) {
|
||||
moveRelative(moveX, moveY, moveZ, this.yaw, pitch, yaw, isOnGround);
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates an entity's rotation. Used in JavaMoveEntityRotTranslator.
|
||||
* @param yaw The new yaw of the entity.
|
||||
* @param pitch The new pitch of the entity.
|
||||
* @param isOnGround Whether the entity is currently on the ground.
|
||||
*/
|
||||
public void updateRotation(float yaw, float pitch, boolean isOnGround) {
|
||||
updatePositionAndRotation(0, 0, 0, yaw, pitch, isOnGround);
|
||||
}
|
||||
|
||||
public final boolean getFlag(EntityFlag flag) {
|
||||
return flags.getFlag(flag);
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates a flag value and determines if the flags would need synced with the Bedrock client.
|
||||
*/
|
||||
public final void setFlag(EntityFlag flag, boolean value) {
|
||||
flagsDirty |= flags.setFlag(flag, value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sends the Bedrock metadata to the client
|
||||
*/
|
||||
public void updateBedrockMetadata() {
|
||||
if (!valid) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (dirtyMetadata.hasEntries() || flagsDirty) {
|
||||
SetEntityDataPacket entityDataPacket = new SetEntityDataPacket();
|
||||
entityDataPacket.setRuntimeEntityId(geyserId);
|
||||
if (flagsDirty) {
|
||||
entityDataPacket.getMetadata().putFlags(flags);
|
||||
flagsDirty = false;
|
||||
}
|
||||
dirtyMetadata.apply(entityDataPacket.getMetadata());
|
||||
session.sendUpstreamPacket(entityDataPacket);
|
||||
}
|
||||
}
|
||||
|
||||
public void setFlags(ByteEntityMetadata entityMetadata) {
|
||||
byte xd = entityMetadata.getPrimitiveValue();
|
||||
setFlag(EntityFlag.ON_FIRE, ((xd & 0x01) == 0x01) && !getFlag(EntityFlag.FIRE_IMMUNE)); // Otherwise immune entities sometimes flicker onfire
|
||||
setFlag(EntityFlag.SNEAKING, (xd & 0x02) == 0x02);
|
||||
setFlag(EntityFlag.SPRINTING, (xd & 0x08) == 0x08);
|
||||
// Swimming is ignored here and instead we rely on the pose
|
||||
setFlag(EntityFlag.GLIDING, (xd & 0x80) == 0x80);
|
||||
|
||||
setInvisible((xd & 0x20) == 0x20);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set a boolean - whether the entity is invisible or visible
|
||||
*
|
||||
* @param value true if the entity is invisible
|
||||
*/
|
||||
protected void setInvisible(boolean value) {
|
||||
setFlag(EntityFlag.INVISIBLE, value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set an int from 0 - this entity's maximum air - (air / maxAir) represents the percentage of bubbles left
|
||||
*/
|
||||
public final void setAir(IntEntityMetadata entityMetadata) {
|
||||
setAirSupply(entityMetadata.getPrimitiveValue());
|
||||
}
|
||||
|
||||
protected void setAirSupply(int amount) {
|
||||
dirtyMetadata.put(EntityData.AIR_SUPPLY, (short) MathUtils.constrain(amount, 0, getMaxAir()));
|
||||
}
|
||||
|
||||
protected int getMaxAir() {
|
||||
return 300;
|
||||
}
|
||||
|
||||
public void setDisplayName(EntityMetadata<Optional<Component>, ?> entityMetadata) {
|
||||
Optional<Component> name = entityMetadata.getValue();
|
||||
if (name.isPresent()) {
|
||||
nametag = MessageTranslator.convertMessage(name.get(), session.getLocale());
|
||||
dirtyMetadata.put(EntityData.NAMETAG, nametag);
|
||||
} else if (!nametag.isEmpty()) {
|
||||
// Clear nametag
|
||||
dirtyMetadata.put(EntityData.NAMETAG, "");
|
||||
}
|
||||
}
|
||||
|
||||
public void setDisplayNameVisible(BooleanEntityMetadata entityMetadata) {
|
||||
dirtyMetadata.put(EntityData.NAMETAG_ALWAYS_SHOW, (byte) (entityMetadata.getPrimitiveValue() ? 1 : 0));
|
||||
}
|
||||
|
||||
public void setGravity(BooleanEntityMetadata entityMetadata) {
|
||||
setFlag(EntityFlag.HAS_GRAVITY, !entityMetadata.getPrimitiveValue());
|
||||
}
|
||||
|
||||
/**
|
||||
* Usually used for bounding box and not animation.
|
||||
*/
|
||||
public void setPose(EntityMetadata<Pose, ?> entityMetadata) {
|
||||
Pose pose = entityMetadata.getValue();
|
||||
|
||||
setFlag(EntityFlag.SLEEPING, pose.equals(Pose.SLEEPING));
|
||||
// Triggered when crawling
|
||||
setFlag(EntityFlag.SWIMMING, pose.equals(Pose.SWIMMING));
|
||||
setDimensions(pose);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the height and width of the entity's bounding box
|
||||
*/
|
||||
protected void setDimensions(Pose pose) {
|
||||
// No flexibility options for basic entities
|
||||
setBoundingBoxHeight(definition.height());
|
||||
setBoundingBoxWidth(definition.width());
|
||||
}
|
||||
|
||||
public void setBoundingBoxHeight(float height) {
|
||||
if (height != boundingBoxHeight) {
|
||||
boundingBoxHeight = height;
|
||||
dirtyMetadata.put(EntityData.BOUNDING_BOX_HEIGHT, boundingBoxHeight);
|
||||
}
|
||||
}
|
||||
|
||||
public void setBoundingBoxWidth(float width) {
|
||||
if (width != boundingBoxWidth) {
|
||||
boundingBoxWidth = width;
|
||||
dirtyMetadata.put(EntityData.BOUNDING_BOX_WIDTH, boundingBoxWidth);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Set a float from 0-1 - how strong the "frozen" overlay should be on screen.
|
||||
*/
|
||||
public float setFreezing(IntEntityMetadata entityMetadata) {
|
||||
// The value that Java edition gives us is in ticks, but Bedrock uses a float percentage of the strength 0.0 -> 1.0
|
||||
// The Java client caps its freezing tick percentage at 140
|
||||
int freezingTicks = Math.min(((IntEntityMetadata) entityMetadata).getPrimitiveValue(), 140);
|
||||
float freezingPercentage = freezingTicks / 140f;
|
||||
dirtyMetadata.put(EntityData.FREEZING_EFFECT_STRENGTH, freezingPercentage);
|
||||
return freezingPercentage;
|
||||
}
|
||||
|
||||
public void setRiderSeatPosition(Vector3f position) {
|
||||
dirtyMetadata.put(EntityData.RIDER_SEAT_POSITION, position);
|
||||
}
|
||||
|
||||
/**
|
||||
* If true, the entity should be shaking on the client's end.
|
||||
*
|
||||
* @return whether {@link EntityFlag#SHAKING} should be set to true.
|
||||
*/
|
||||
protected boolean isShaking() {
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* x = Pitch, y = HeadYaw, z = Yaw
|
||||
*
|
||||
* @return the bedrock rotation
|
||||
*/
|
||||
public Vector3f getBedrockRotation() {
|
||||
return Vector3f.from(pitch, headYaw, yaw);
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public <I extends Entity> I as(Class<I> entityClass) {
|
||||
return entityClass.isInstance(this) ? (I) this : null;
|
||||
}
|
||||
|
||||
public <I extends Entity> boolean is(Class<I> entityClass) {
|
||||
return entityClass.isInstance(this);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,158 @@
|
|||
/*
|
||||
* Copyright (c) 2019-2021 GeyserMC. http://geysermc.org
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*
|
||||
* @author GeyserMC
|
||||
* @link https://github.com/GeyserMC/Geyser
|
||||
*/
|
||||
|
||||
package org.geysermc.connector.entity;
|
||||
|
||||
import com.github.steveice10.mc.protocol.data.game.entity.metadata.EntityMetadata;
|
||||
import com.github.steveice10.mc.protocol.data.game.entity.metadata.MetadataType;
|
||||
import com.github.steveice10.mc.protocol.data.game.entity.type.EntityType;
|
||||
import it.unimi.dsi.fastutil.objects.ObjectArrayList;
|
||||
import lombok.Setter;
|
||||
import lombok.experimental.Accessors;
|
||||
import org.geysermc.connector.GeyserConnector;
|
||||
import org.geysermc.connector.entity.factory.BaseEntityFactory;
|
||||
import org.geysermc.connector.entity.factory.EntityFactory;
|
||||
import org.geysermc.connector.registry.Registries;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.function.BiConsumer;
|
||||
|
||||
/**
|
||||
* Represents data for an entity. This includes properties such as height and width, as well as the list of entity
|
||||
* metadata translators needed to translate the properties sent from the server. The translators are structured in such
|
||||
* a way that inserting a new one (for example in version updates) is convenient.
|
||||
*
|
||||
* @param <T> the entity type this definition represents
|
||||
*/
|
||||
public record EntityDefinition<T extends Entity>(EntityFactory<T> factory, EntityType entityType, String identifier,
|
||||
float width, float height, float offset, List<EntityMetadataTranslator<? super T, ?, ?>> translators) {
|
||||
|
||||
public static <T extends Entity> Builder<T> inherited(BaseEntityFactory<T> factory, EntityDefinition<? super T> parent) {
|
||||
return inherited((EntityFactory<T>) factory, parent);
|
||||
}
|
||||
|
||||
public static <T extends Entity> Builder<T> inherited(EntityFactory<T> factory, EntityDefinition<? super T> parent) {
|
||||
return new Builder<>(factory, parent.entityType, parent.identifier, parent.width, parent.height, parent.offset, new ObjectArrayList<>(parent.translators));
|
||||
}
|
||||
|
||||
public static <T extends Entity> Builder<T> builder(EntityFactory<T> factory) {
|
||||
return new Builder<>(factory);
|
||||
}
|
||||
|
||||
|
||||
public <M> void translateMetadata(T entity, EntityMetadata<M, ? extends MetadataType<M>> metadata) {
|
||||
EntityMetadataTranslator<? super T, M, EntityMetadata<M, ? extends MetadataType<M>>> translator = (EntityMetadataTranslator<? super T, M, EntityMetadata<M, ? extends MetadataType<M>>>) this.translators.get(metadata.getId());
|
||||
if (translator == null) {
|
||||
// This can safely happen; it means we don't translate this entity metadata
|
||||
return;
|
||||
}
|
||||
|
||||
if (translator.acceptedType() != metadata.getType()) {
|
||||
GeyserConnector.getInstance().getLogger().warning("Metadata ID " + metadata.getId() + " was received with type " + metadata.getType() + " but we expected " + translator.acceptedType() + " for " + entity.getDefinition().entityType());
|
||||
if (GeyserConnector.getInstance().getConfig().isDebugMode()) {
|
||||
GeyserConnector.getInstance().getLogger().debug(metadata.toString());
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
translator.translateFunction().accept(entity, metadata);
|
||||
}
|
||||
|
||||
@Setter
|
||||
@Accessors(fluent = true, chain = true)
|
||||
public static class Builder<T extends Entity> {
|
||||
private final EntityFactory<T> factory;
|
||||
private EntityType type;
|
||||
private String identifier;
|
||||
private float width;
|
||||
private float height;
|
||||
private float offset;
|
||||
private final List<EntityMetadataTranslator<? super T, ?, ?>> translators;
|
||||
|
||||
private Builder(EntityFactory<T> factory) {
|
||||
this.factory = factory;
|
||||
translators = new ObjectArrayList<>();
|
||||
}
|
||||
|
||||
public Builder(EntityFactory<T> factory, EntityType type, String identifier, float width, float height, float offset, List<EntityMetadataTranslator<? super T, ?, ?>> translators) {
|
||||
this.factory = factory;
|
||||
this.type = type;
|
||||
this.identifier = identifier;
|
||||
this.width = width;
|
||||
this.height = height;
|
||||
this.offset = offset;
|
||||
this.translators = translators;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the height and width as one value
|
||||
*/
|
||||
public Builder<T> heightAndWidth(float value) {
|
||||
height = value;
|
||||
width = value;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Resets the identifier as well
|
||||
*/
|
||||
public Builder<T> type(EntityType type) {
|
||||
this.type = type;
|
||||
identifier = null;
|
||||
return this;
|
||||
}
|
||||
|
||||
public <U, EM extends EntityMetadata<U, ? extends MetadataType<U>>> Builder<T> addTranslator(MetadataType<U> type, BiConsumer<T, EM> translateFunction) {
|
||||
translators.add(new EntityMetadataTranslator<>(type, translateFunction));
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder<T> addTranslator(EntityMetadataTranslator<T, ?, ?> translator) {
|
||||
translators.add(translator);
|
||||
return this;
|
||||
}
|
||||
|
||||
public EntityDefinition<T> build() {
|
||||
return build(true);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param register whether to register this entity in the Registries for entity types. Generally this should be
|
||||
* set to false if we're not expecting this entity to spawn from the network.
|
||||
*/
|
||||
public EntityDefinition<T> build(boolean register) {
|
||||
if (identifier == null && type != null) {
|
||||
identifier = "minecraft:" + type.name().toLowerCase(Locale.ROOT);
|
||||
}
|
||||
EntityDefinition<T> definition = new EntityDefinition<>(factory, type, identifier, width, height, offset, translators);
|
||||
if (register && definition.entityType() != null) {
|
||||
Registries.ENTITY_DEFINITIONS.get().putIfAbsent(definition.entityType(), definition);
|
||||
Registries.JAVA_ENTITY_IDENTIFIERS.get().putIfAbsent("minecraft:" + type.name().toLowerCase(Locale.ROOT), definition);
|
||||
}
|
||||
return definition;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,904 @@
|
|||
/*
|
||||
* Copyright (c) 2019-2021 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.MetadataType;
|
||||
import com.github.steveice10.mc.protocol.data.game.entity.metadata.type.BooleanEntityMetadata;
|
||||
import com.github.steveice10.mc.protocol.data.game.entity.metadata.type.FloatEntityMetadata;
|
||||
import com.github.steveice10.mc.protocol.data.game.entity.type.EntityType;
|
||||
import com.nukkitx.protocol.bedrock.data.entity.EntityData;
|
||||
import com.nukkitx.protocol.bedrock.data.entity.EntityFlag;
|
||||
import org.geysermc.connector.entity.factory.BaseEntityFactory;
|
||||
import org.geysermc.connector.entity.factory.ExperienceOrbEntityFactory;
|
||||
import org.geysermc.connector.entity.factory.PaintingEntityFactory;
|
||||
import org.geysermc.connector.entity.living.*;
|
||||
import org.geysermc.connector.entity.living.animal.*;
|
||||
import org.geysermc.connector.entity.living.animal.horse.*;
|
||||
import org.geysermc.connector.entity.living.animal.tameable.CatEntity;
|
||||
import org.geysermc.connector.entity.living.animal.tameable.ParrotEntity;
|
||||
import org.geysermc.connector.entity.living.animal.tameable.TameableEntity;
|
||||
import org.geysermc.connector.entity.living.animal.tameable.WolfEntity;
|
||||
import org.geysermc.connector.entity.living.merchant.AbstractMerchantEntity;
|
||||
import org.geysermc.connector.entity.living.merchant.VillagerEntity;
|
||||
import org.geysermc.connector.entity.living.monster.*;
|
||||
import org.geysermc.connector.entity.living.monster.raid.PillagerEntity;
|
||||
import org.geysermc.connector.entity.living.monster.raid.RaidParticipantEntity;
|
||||
import org.geysermc.connector.entity.living.monster.raid.SpellcasterIllagerEntity;
|
||||
import org.geysermc.connector.entity.living.monster.raid.VindicatorEntity;
|
||||
import org.geysermc.connector.entity.player.PlayerEntity;
|
||||
import org.geysermc.connector.network.translators.chat.MessageTranslator;
|
||||
import org.geysermc.connector.registry.Registries;
|
||||
|
||||
public final class EntityDefinitions {
|
||||
public static final EntityDefinition<AreaEffectCloudEntity> AREA_EFFECT_CLOUD;
|
||||
public static final EntityDefinition<ArmorStandEntity> ARMOR_STAND;
|
||||
public static final EntityDefinition<TippedArrowEntity> ARROW;
|
||||
public static final EntityDefinition<AxolotlEntity> AXOLOTL;
|
||||
public static final EntityDefinition<BatEntity> BAT;
|
||||
public static final EntityDefinition<BeeEntity> BEE;
|
||||
public static final EntityDefinition<BlazeEntity> BLAZE;
|
||||
public static final EntityDefinition<BoatEntity> BOAT;
|
||||
public static final EntityDefinition<CatEntity> CAT;
|
||||
public static final EntityDefinition<MonsterEntity> CAVE_SPIDER;
|
||||
public static final EntityDefinition<ChickenEntity> CHICKEN;
|
||||
public static final EntityDefinition<CreeperEntity> CREEPER;
|
||||
public static final EntityDefinition<AbstractFishEntity> COD;
|
||||
public static final EntityDefinition<AnimalEntity> COW;
|
||||
public static final EntityDefinition<ChestedHorseEntity> DONKEY;
|
||||
public static final EntityDefinition<WaterEntity> DOLPHIN;
|
||||
public static final EntityDefinition<ItemedFireballEntity> DRAGON_FIREBALL;
|
||||
public static final EntityDefinition<ZombieEntity> DROWNED;
|
||||
public static final EntityDefinition<ElderGuardianEntity> ELDER_GUARDIAN;
|
||||
public static final EntityDefinition<EndermanEntity> ENDERMAN;
|
||||
public static final EntityDefinition<MonsterEntity> ENDERMITE;
|
||||
public static final EntityDefinition<EnderDragonEntity> ENDER_DRAGON;
|
||||
public static final EntityDefinition<EnderCrystalEntity> END_CRYSTAL;
|
||||
public static final EntityDefinition<SpellcasterIllagerEntity> EVOKER;
|
||||
public static final EntityDefinition<Entity> EVOKER_FANGS;
|
||||
public static final EntityDefinition<ExpOrbEntity> EXPERIENCE_ORB;
|
||||
public static final EntityDefinition<Entity> EYE_OF_ENDER;
|
||||
public static final EntityDefinition<FallingBlockEntity> FALLING_BLOCK;
|
||||
public static final EntityDefinition<ItemedFireballEntity> FIREBALL;
|
||||
public static final EntityDefinition<FishingHookEntity> FISHING_BOBBER;
|
||||
public static final EntityDefinition<FireworkEntity> FIREWORK_ROCKET;
|
||||
public static final EntityDefinition<FoxEntity> FOX;
|
||||
public static final EntityDefinition<GiantEntity> GIANT;
|
||||
public static final EntityDefinition<GhastEntity> GHAST;
|
||||
public static final EntityDefinition<ItemFrameEntity> GLOW_ITEM_FRAME;
|
||||
public static final EntityDefinition<GlowSquidEntity> GLOW_SQUID;
|
||||
public static final EntityDefinition<GoatEntity> GOAT;
|
||||
public static final EntityDefinition<GuardianEntity> GUARDIAN;
|
||||
public static final EntityDefinition<HoglinEntity> HOGLIN;
|
||||
public static final EntityDefinition<HorseEntity> HORSE;
|
||||
public static final EntityDefinition<ZombieEntity> HUSK;
|
||||
public static final EntityDefinition<SpellcasterIllagerEntity> ILLUSIONER; // Not present on Bedrock
|
||||
public static final EntityDefinition<IronGolemEntity> IRON_GOLEM;
|
||||
public static final EntityDefinition<ItemEntity> ITEM;
|
||||
public static final EntityDefinition<ItemFrameEntity> ITEM_FRAME;
|
||||
public static final EntityDefinition<LeashKnotEntity> LEASH_KNOT;
|
||||
public static final EntityDefinition<LightningEntity> LIGHTNING_BOLT;
|
||||
public static final EntityDefinition<LlamaEntity> LLAMA;
|
||||
public static final EntityDefinition<ThrowableEntity> LLAMA_SPIT;
|
||||
public static final EntityDefinition<MagmaCubeEntity> MAGMA_CUBE;
|
||||
public static final EntityDefinition<MinecartEntity> MINECART;
|
||||
public static final EntityDefinition<MinecartEntity> MINECART_CHEST;
|
||||
public static final EntityDefinition<CommandBlockMinecartEntity> MINECART_COMMAND_BLOCK;
|
||||
public static final EntityDefinition<MinecartEntity> MINECART_HOPPER;
|
||||
public static final EntityDefinition<FurnaceMinecartEntity> MINECART_FURNACE; // Not present on Bedrock
|
||||
public static final EntityDefinition<SpawnerMinecartEntity> MINECART_SPAWNER; // Not present on Bedrock
|
||||
public static final EntityDefinition<MinecartEntity> MINECART_TNT;
|
||||
public static final EntityDefinition<MooshroomEntity> MOOSHROOM;
|
||||
public static final EntityDefinition<ChestedHorseEntity> MULE;
|
||||
public static final EntityDefinition<OcelotEntity> OCELOT;
|
||||
public static final EntityDefinition<PaintingEntity> PAINTING;
|
||||
public static final EntityDefinition<PandaEntity> PANDA;
|
||||
public static final EntityDefinition<ParrotEntity> PARROT;
|
||||
public static final EntityDefinition<PhantomEntity> PHANTOM;
|
||||
public static final EntityDefinition<PigEntity> PIG;
|
||||
public static final EntityDefinition<PiglinEntity> PIGLIN;
|
||||
public static final EntityDefinition<BasePiglinEntity> PIGLIN_BRUTE;
|
||||
public static final EntityDefinition<PillagerEntity> PILLAGER;
|
||||
public static final EntityDefinition<PlayerEntity> PLAYER;
|
||||
public static final EntityDefinition<PolarBearEntity> POLAR_BEAR;
|
||||
public static final EntityDefinition<TNTEntity> PRIMED_TNT;
|
||||
public static final EntityDefinition<PufferFishEntity> PUFFERFISH;
|
||||
public static final EntityDefinition<RabbitEntity> RABBIT;
|
||||
public static final EntityDefinition<RaidParticipantEntity> RAVAGER;
|
||||
public static final EntityDefinition<AbstractFishEntity> SALMON;
|
||||
public static final EntityDefinition<SheepEntity> SHEEP;
|
||||
public static final EntityDefinition<ShulkerEntity> SHULKER;
|
||||
public static final EntityDefinition<ThrowableEntity> SHULKER_BULLET;
|
||||
public static final EntityDefinition<MonsterEntity> SILVERFISH;
|
||||
public static final EntityDefinition<SkeletonEntity> SKELETON;
|
||||
public static final EntityDefinition<AbstractHorseEntity> SKELETON_HORSE;
|
||||
public static final EntityDefinition<SlimeEntity> SLIME;
|
||||
public static final EntityDefinition<ItemedFireballEntity> SMALL_FIREBALL;
|
||||
public static final EntityDefinition<ThrowableItemEntity> SNOWBALL;
|
||||
public static final EntityDefinition<SnowGolemEntity> SNOW_GOLEM;
|
||||
public static final EntityDefinition<AbstractArrowEntity> SPECTRAL_ARROW;
|
||||
public static final EntityDefinition<SpiderEntity> SPIDER;
|
||||
public static final EntityDefinition<SquidEntity> SQUID;
|
||||
public static final EntityDefinition<AbstractSkeletonEntity> STRAY;
|
||||
public static final EntityDefinition<StriderEntity> STRIDER;
|
||||
public static final EntityDefinition<ThrowableItemEntity> THROWN_EGG;
|
||||
public static final EntityDefinition<ThrowableItemEntity> THROWN_ENDERPEARL;
|
||||
public static final EntityDefinition<ThrowableItemEntity> THROWN_EXP_BOTTLE;
|
||||
public static final EntityDefinition<ThrownPotionEntity> THROWN_POTION;
|
||||
public static final EntityDefinition<TropicalFishEntity> TROPICAL_FISH;
|
||||
public static final EntityDefinition<TurtleEntity> TURTLE;
|
||||
public static final EntityDefinition<TraderLlamaEntity> TRADER_LLAMA;
|
||||
public static final EntityDefinition<TridentEntity> TRIDENT;
|
||||
public static final EntityDefinition<AbstractMerchantEntity> WANDERING_TRADER;
|
||||
public static final EntityDefinition<RaidParticipantEntity> WITCH;
|
||||
public static final EntityDefinition<WitherEntity> WITHER;
|
||||
public static final EntityDefinition<AbstractSkeletonEntity> WITHER_SKELETON;
|
||||
public static final EntityDefinition<WitherSkullEntity> WITHER_SKULL;
|
||||
public static final EntityDefinition<WolfEntity> WOLF;
|
||||
public static final EntityDefinition<VillagerEntity> VILLAGER;
|
||||
public static final EntityDefinition<VindicatorEntity> VINDICATOR;
|
||||
public static final EntityDefinition<VexEntity> VEX;
|
||||
public static final EntityDefinition<ZoglinEntity> ZOGLIN;
|
||||
public static final EntityDefinition<ZombieEntity> ZOMBIE;
|
||||
public static final EntityDefinition<AbstractHorseEntity> ZOMBIE_HORSE;
|
||||
public static final EntityDefinition<ZombieVillagerEntity> ZOMBIE_VILLAGER;
|
||||
public static final EntityDefinition<ZombifiedPiglinEntity> ZOMBIFIED_PIGLIN;
|
||||
|
||||
/**
|
||||
* Is not sent over the network
|
||||
*/
|
||||
public static final EntityDefinition<EnderDragonPartEntity> ENDER_DRAGON_PART;
|
||||
/**
|
||||
* Special Bedrock type
|
||||
*/
|
||||
public static final EntityDefinition<WitherSkullEntity> WITHER_SKULL_DANGEROUS;
|
||||
|
||||
static {
|
||||
EntityDefinition<Entity> entityBase = EntityDefinition.builder((BaseEntityFactory<Entity>) Entity::new)
|
||||
.addTranslator(MetadataType.BYTE, Entity::setFlags)
|
||||
.addTranslator(MetadataType.INT, Entity::setAir) // Air/bubbles
|
||||
.addTranslator(MetadataType.OPTIONAL_CHAT, Entity::setDisplayName)
|
||||
.addTranslator(MetadataType.BOOLEAN, Entity::setDisplayNameVisible)
|
||||
.addTranslator(MetadataType.BOOLEAN, (entity, entityMetadata) -> entity.setFlag(EntityFlag.SILENT, ((BooleanEntityMetadata) entityMetadata).getPrimitiveValue()))
|
||||
.addTranslator(MetadataType.BOOLEAN, Entity::setGravity)
|
||||
.addTranslator(MetadataType.POSE, Entity::setPose)
|
||||
.addTranslator(MetadataType.INT, Entity::setFreezing)
|
||||
.build();
|
||||
|
||||
// Extends entity
|
||||
{
|
||||
AREA_EFFECT_CLOUD = EntityDefinition.inherited(AreaEffectCloudEntity::new, entityBase)
|
||||
.type(EntityType.AREA_EFFECT_CLOUD)
|
||||
.height(0.5f).width(1.0f)
|
||||
.addTranslator(MetadataType.FLOAT, AreaEffectCloudEntity::setRadius)
|
||||
.addTranslator(MetadataType.INT, (entity, entityMetadata) -> entity.getDirtyMetadata().put(EntityData.EFFECT_COLOR, entityMetadata.getValue()))
|
||||
.addTranslator(null) // Waiting
|
||||
.addTranslator(MetadataType.PARTICLE, AreaEffectCloudEntity::setParticle)
|
||||
.build();
|
||||
BOAT = EntityDefinition.inherited(BoatEntity::new, entityBase)
|
||||
.type(EntityType.BOAT)
|
||||
.height(0.6f).width(1.6f)
|
||||
.offset(0.35f)
|
||||
.addTranslator(MetadataType.INT, (boatEntity, entityMetadata) -> boatEntity.getDirtyMetadata().put(EntityData.HURT_TIME, entityMetadata.getValue())) // Time since last hit
|
||||
.addTranslator(MetadataType.INT, (boatEntity, entityMetadata) -> boatEntity.getDirtyMetadata().put(EntityData.HURT_DIRECTION, entityMetadata.getValue())) // Rocking direction
|
||||
.addTranslator(MetadataType.FLOAT, (boatEntity, entityMetadata) ->
|
||||
// 'Health' in Bedrock, damage taken in Java - it makes motion in Bedrock
|
||||
boatEntity.getDirtyMetadata().put(EntityData.HEALTH, 40 - ((int) ((FloatEntityMetadata) entityMetadata).getPrimitiveValue())))
|
||||
.addTranslator(MetadataType.INT, BoatEntity::setVariant)
|
||||
.addTranslator(MetadataType.BOOLEAN, BoatEntity::setPaddlingLeft)
|
||||
.addTranslator(MetadataType.BOOLEAN, BoatEntity::setPaddlingRight)
|
||||
.addTranslator(MetadataType.INT, (boatEntity, entityMetadata) -> boatEntity.getDirtyMetadata().put(EntityData.BOAT_BUBBLE_TIME, entityMetadata.getValue())) // May not actually do anything
|
||||
.build();
|
||||
DRAGON_FIREBALL = EntityDefinition.inherited(ItemedFireballEntity::new, entityBase)
|
||||
.type(EntityType.DRAGON_FIREBALL)
|
||||
.heightAndWidth(1.0f)
|
||||
.build();
|
||||
END_CRYSTAL = EntityDefinition.inherited(EnderCrystalEntity::new, entityBase)
|
||||
.type(EntityType.END_CRYSTAL)
|
||||
.heightAndWidth(2.0f)
|
||||
.addTranslator(MetadataType.OPTIONAL_POSITION, EnderCrystalEntity::setBlockTarget)
|
||||
.addTranslator(MetadataType.BOOLEAN,
|
||||
(enderCrystalEntity, entityMetadata) -> enderCrystalEntity.setFlag(EntityFlag.SHOW_BOTTOM, ((BooleanEntityMetadata) entityMetadata).getPrimitiveValue())) // There is a base located on the ender crystal
|
||||
.build();
|
||||
EXPERIENCE_ORB = EntityDefinition.inherited((ExperienceOrbEntityFactory) ExpOrbEntity::new, entityBase)
|
||||
.type(EntityType.EXPERIENCE_ORB)
|
||||
.identifier("minecraft:xp_orb")
|
||||
.build();
|
||||
EVOKER_FANGS = EntityDefinition.inherited(entityBase.factory(), entityBase)
|
||||
.type(EntityType.EVOKER_FANGS)
|
||||
.height(0.8f).width(0.5f)
|
||||
.identifier("minecraft:evocation_fang")
|
||||
.build();
|
||||
EYE_OF_ENDER = EntityDefinition.inherited(Entity::new, entityBase)
|
||||
.type(EntityType.EYE_OF_ENDER)
|
||||
.heightAndWidth(0.25f)
|
||||
.identifier("minecraft:eye_of_ender_signal")
|
||||
.build();
|
||||
FALLING_BLOCK = EntityDefinition.<FallingBlockEntity>inherited(null, entityBase)
|
||||
.type(EntityType.FALLING_BLOCK)
|
||||
.heightAndWidth(0.98f)
|
||||
.addTranslator(null) // "start block position"
|
||||
.build();
|
||||
FIREBALL = EntityDefinition.inherited(ItemedFireballEntity::new, entityBase)
|
||||
.type(EntityType.FIREBALL)
|
||||
.heightAndWidth(1.0f)
|
||||
.build();
|
||||
FIREWORK_ROCKET = EntityDefinition.inherited(FireworkEntity::new, entityBase)
|
||||
.type(EntityType.FIREWORK_ROCKET)
|
||||
.heightAndWidth(0.25f)
|
||||
.identifier("minecraft:fireworks_rocket")
|
||||
.addTranslator(MetadataType.ITEM, FireworkEntity::setFireworkItem)
|
||||
.addTranslator(MetadataType.OPTIONAL_VARINT, FireworkEntity::setPlayerGliding)
|
||||
.addTranslator(null) // Shot at angle
|
||||
.build();
|
||||
FISHING_BOBBER = EntityDefinition.<FishingHookEntity>inherited(null, entityBase)
|
||||
.type(EntityType.FISHING_BOBBER)
|
||||
.identifier("minecraft:fishing_book")
|
||||
.addTranslator(MetadataType.INT, FishingHookEntity::setHookedEntity)
|
||||
.build();
|
||||
ITEM = EntityDefinition.inherited(ItemEntity::new, entityBase)
|
||||
.type(EntityType.ITEM)
|
||||
.heightAndWidth(0.25f)
|
||||
.offset(0.125f)
|
||||
.addTranslator(MetadataType.ITEM, ItemEntity::setItem)
|
||||
.build();
|
||||
LEASH_KNOT = EntityDefinition.inherited(LeashKnotEntity::new, entityBase)
|
||||
.type(EntityType.LEASH_KNOT)
|
||||
.height(0.5f).width(0.375f)
|
||||
.build();
|
||||
LIGHTNING_BOLT = EntityDefinition.inherited(LightningEntity::new, entityBase)
|
||||
.type(EntityType.LIGHTNING_BOLT)
|
||||
.build();
|
||||
LLAMA_SPIT = EntityDefinition.inherited(ThrowableEntity::new, entityBase)
|
||||
.type(EntityType.LLAMA_SPIT)
|
||||
.heightAndWidth(0.25f)
|
||||
.build();
|
||||
PAINTING = EntityDefinition.inherited((PaintingEntityFactory) PaintingEntity::new, entityBase)
|
||||
.type(EntityType.PAINTING)
|
||||
.build();
|
||||
PRIMED_TNT = EntityDefinition.inherited(TNTEntity::new, entityBase)
|
||||
.type(EntityType.PRIMED_TNT)
|
||||
.heightAndWidth(0.98f)
|
||||
.identifier("minecraft:tnt")
|
||||
.addTranslator(MetadataType.INT, TNTEntity::setFuseLength)
|
||||
.build();
|
||||
SHULKER_BULLET = EntityDefinition.inherited(ThrowableEntity::new, entityBase)
|
||||
.type(EntityType.SHULKER_BULLET)
|
||||
.heightAndWidth(0.3125f)
|
||||
.build();
|
||||
SMALL_FIREBALL = EntityDefinition.inherited(ItemedFireballEntity::new, entityBase)
|
||||
.type(EntityType.SMALL_FIREBALL)
|
||||
.heightAndWidth(0.3125f)
|
||||
.build();
|
||||
SNOWBALL = EntityDefinition.inherited(ThrowableItemEntity::new, entityBase)
|
||||
.type(EntityType.SNOWBALL)
|
||||
.heightAndWidth(0.25f)
|
||||
.build();
|
||||
THROWN_ENDERPEARL = EntityDefinition.inherited(ThrowableItemEntity::new, entityBase)
|
||||
.type(EntityType.THROWN_ENDERPEARL)
|
||||
.heightAndWidth(0.25f)
|
||||
.identifier("minecraft:ender_pearl")
|
||||
.build();
|
||||
THROWN_EGG = EntityDefinition.inherited(ThrowableItemEntity::new, entityBase)
|
||||
.type(EntityType.THROWN_EGG)
|
||||
.heightAndWidth(0.25f)
|
||||
.identifier("minecraft:egg")
|
||||
.build();
|
||||
THROWN_EXP_BOTTLE = EntityDefinition.inherited(ThrowableItemEntity::new, entityBase)
|
||||
.type(EntityType.THROWN_EXP_BOTTLE)
|
||||
.heightAndWidth(0.25f)
|
||||
.identifier("minecraft:xp_bottle")
|
||||
.build();
|
||||
THROWN_POTION = EntityDefinition.inherited(ThrownPotionEntity::new, entityBase)
|
||||
.type(EntityType.THROWN_POTION)
|
||||
.heightAndWidth(0.25f)
|
||||
.identifier("minecraft:splash_potion")
|
||||
.addTranslator(MetadataType.ITEM, ThrownPotionEntity::setPotion)
|
||||
.build();
|
||||
|
||||
EntityDefinition<AbstractArrowEntity> abstractArrowBase = EntityDefinition.inherited(AbstractArrowEntity::new, entityBase)
|
||||
.addTranslator(MetadataType.BYTE, AbstractArrowEntity::setArrowFlags)
|
||||
.addTranslator(null) // "Piercing level"
|
||||
.build();
|
||||
ARROW = EntityDefinition.inherited(TippedArrowEntity::new, abstractArrowBase)
|
||||
.type(EntityType.ARROW)
|
||||
.heightAndWidth(0.25f)
|
||||
.addTranslator(MetadataType.INT, TippedArrowEntity::setPotionEffectColor)
|
||||
.build();
|
||||
SPECTRAL_ARROW = EntityDefinition.inherited(abstractArrowBase.factory(), abstractArrowBase)
|
||||
.type(EntityType.SPECTRAL_ARROW)
|
||||
.heightAndWidth(0.25f)
|
||||
.identifier("minecraft:arrow")
|
||||
.build();
|
||||
TRIDENT = EntityDefinition.inherited(TridentEntity::new, abstractArrowBase) // TODO remove class
|
||||
.type(EntityType.TRIDENT)
|
||||
.identifier("minecraft:thrown_trident")
|
||||
.addTranslator(null) // Loyalty
|
||||
.addTranslator(MetadataType.BOOLEAN, (tridentEntity, entityMetadata) -> tridentEntity.setFlag(EntityFlag.ENCHANTED, ((BooleanEntityMetadata) entityMetadata).getPrimitiveValue()))
|
||||
.build();
|
||||
|
||||
// Item frames are handled differently as they are blocks, not items, in Bedrock
|
||||
ITEM_FRAME = EntityDefinition.<ItemFrameEntity>inherited(null, entityBase)
|
||||
.type(EntityType.ITEM_FRAME)
|
||||
.addTranslator(MetadataType.ITEM, ItemFrameEntity::setItemInFrame)
|
||||
.addTranslator(MetadataType.INT, ItemFrameEntity::setItemRotation)
|
||||
.build();
|
||||
GLOW_ITEM_FRAME = EntityDefinition.inherited(ITEM_FRAME.factory(), ITEM_FRAME)
|
||||
.type(EntityType.GLOW_ITEM_FRAME)
|
||||
.build();
|
||||
|
||||
MINECART = EntityDefinition.inherited(MinecartEntity::new, entityBase)
|
||||
.type(EntityType.MINECART)
|
||||
.height(0.7f).width(0.98f)
|
||||
.offset(0.35f)
|
||||
.addTranslator(MetadataType.INT, (minecartEntity, entityMetadata) -> minecartEntity.getDirtyMetadata().put(EntityData.HEALTH, entityMetadata.getValue()))
|
||||
.addTranslator(MetadataType.INT, (minecartEntity, entityMetadata) -> minecartEntity.getDirtyMetadata().put(EntityData.HURT_DIRECTION, entityMetadata.getValue())) // Direction in which the minecart is shaking
|
||||
.addTranslator(MetadataType.FLOAT, (minecartEntity, entityMetadata) ->
|
||||
// Power in Java, time in Bedrock
|
||||
minecartEntity.getDirtyMetadata().put(EntityData.HURT_TIME, Math.min((int) ((FloatEntityMetadata) entityMetadata).getPrimitiveValue(), 15)))
|
||||
.addTranslator(MetadataType.INT, MinecartEntity::setCustomBlock)
|
||||
.addTranslator(MetadataType.INT, MinecartEntity::setCustomBlockOffset)
|
||||
.addTranslator(MetadataType.BOOLEAN, MinecartEntity::setShowCustomBlock)
|
||||
.build();
|
||||
MINECART_CHEST = EntityDefinition.inherited(MINECART.factory(), MINECART)
|
||||
.type(EntityType.MINECART_CHEST)
|
||||
.identifier("minecraft:chest_minecart")
|
||||
.build();
|
||||
MINECART_COMMAND_BLOCK = EntityDefinition.inherited(CommandBlockMinecartEntity::new, MINECART)
|
||||
.type(EntityType.MINECART_COMMAND_BLOCK)
|
||||
.identifier("minecraft:command_block_minecart")
|
||||
.addTranslator(MetadataType.STRING, (entity, entityMetadata) -> entity.getDirtyMetadata().put(EntityData.COMMAND_BLOCK_COMMAND, entityMetadata.getValue()))
|
||||
.addTranslator(MetadataType.CHAT, (entity, entityMetadata) -> entity.getDirtyMetadata().put(EntityData.COMMAND_BLOCK_LAST_OUTPUT, MessageTranslator.convertMessage(entityMetadata.getValue())))
|
||||
.build();
|
||||
MINECART_FURNACE = EntityDefinition.inherited(FurnaceMinecartEntity::new, MINECART)
|
||||
.type(EntityType.MINECART_FURNACE)
|
||||
.identifier("minecraft:minecart")
|
||||
.addTranslator(MetadataType.BOOLEAN, FurnaceMinecartEntity::setHasFuel)
|
||||
.build();
|
||||
MINECART_HOPPER = EntityDefinition.inherited(MINECART.factory(), MINECART)
|
||||
.type(EntityType.MINECART_HOPPER)
|
||||
.identifier("minecraft:hopper_minecart")
|
||||
.build();
|
||||
MINECART_SPAWNER = EntityDefinition.inherited(SpawnerMinecartEntity::new, MINECART)
|
||||
.type(EntityType.MINECART_SPAWNER)
|
||||
.identifier("minecraft:minecart")
|
||||
.build();
|
||||
MINECART_TNT = EntityDefinition.inherited(MINECART.factory(), MINECART)
|
||||
.type(EntityType.MINECART_TNT)
|
||||
.identifier("minecraft:tnt_minecart")
|
||||
.build();
|
||||
|
||||
WITHER_SKULL = EntityDefinition.inherited(WitherSkullEntity::new, entityBase)
|
||||
.type(EntityType.WITHER_SKULL)
|
||||
.heightAndWidth(0.3125f)
|
||||
.addTranslator(MetadataType.BOOLEAN, WitherSkullEntity::setDangerous)
|
||||
.build();
|
||||
WITHER_SKULL_DANGEROUS = EntityDefinition.inherited(WITHER_SKULL.factory(), WITHER_SKULL)
|
||||
.build(false);
|
||||
}
|
||||
|
||||
EntityDefinition<LivingEntity> livingEntityBase = EntityDefinition.inherited(LivingEntity::new, entityBase)
|
||||
.addTranslator(MetadataType.BYTE, LivingEntity::setLivingEntityFlags)
|
||||
.addTranslator(MetadataType.FLOAT, LivingEntity::setHealth)
|
||||
.addTranslator(MetadataType.INT,
|
||||
(livingEntity, entityMetadata) -> livingEntity.getDirtyMetadata().put(EntityData.EFFECT_COLOR, entityMetadata.getValue()))
|
||||
.addTranslator(MetadataType.BOOLEAN,
|
||||
(livingEntity, entityMetadata) -> livingEntity.getDirtyMetadata().put(EntityData.EFFECT_AMBIENT, (byte) (((BooleanEntityMetadata) entityMetadata).getPrimitiveValue() ? 1 : 0)))
|
||||
.addTranslator(null) // Arrow count
|
||||
.addTranslator(null) // Stinger count
|
||||
.addTranslator(MetadataType.OPTIONAL_POSITION, LivingEntity::setBedPosition)
|
||||
.build();
|
||||
|
||||
ARMOR_STAND = EntityDefinition.inherited(ArmorStandEntity::new, livingEntityBase)
|
||||
.type(EntityType.ARMOR_STAND)
|
||||
.height(1.975f).width(0.5f)
|
||||
.addTranslator(MetadataType.BYTE, ArmorStandEntity::setArmorStandFlags)
|
||||
.addTranslator(MetadataType.ROTATION, ArmorStandEntity::setHeadRotation)
|
||||
.addTranslator(MetadataType.ROTATION, ArmorStandEntity::setBodyRotation)
|
||||
.addTranslator(MetadataType.ROTATION, ArmorStandEntity::setLeftArmRotation)
|
||||
.addTranslator(MetadataType.ROTATION, ArmorStandEntity::setRightArmRotation)
|
||||
.addTranslator(MetadataType.ROTATION, ArmorStandEntity::setLeftLegRotation)
|
||||
.addTranslator(MetadataType.ROTATION, ArmorStandEntity::setRightLegRotation)
|
||||
.build();
|
||||
PLAYER = EntityDefinition.<PlayerEntity>inherited(null, livingEntityBase)
|
||||
.type(EntityType.PLAYER)
|
||||
.height(1.8f).width(0.6f)
|
||||
.offset(1.62f)
|
||||
.addTranslator(MetadataType.FLOAT, PlayerEntity::setAbsorptionHearts)
|
||||
.addTranslator(null) // Player score
|
||||
.addTranslator(MetadataType.BYTE, PlayerEntity::setSkinVisibility)
|
||||
.addTranslator(null) // Player main hand
|
||||
.addTranslator(MetadataType.NBT_TAG, PlayerEntity::setLeftParrot)
|
||||
.addTranslator(MetadataType.NBT_TAG, PlayerEntity::setRightParrot)
|
||||
.build();
|
||||
|
||||
EntityDefinition<MobEntity> mobEntityBase = EntityDefinition.inherited(MobEntity::new, livingEntityBase)
|
||||
.addTranslator(MetadataType.BYTE, MobEntity::setMobFlags)
|
||||
.build();
|
||||
|
||||
// Extends mob
|
||||
{
|
||||
BAT = EntityDefinition.inherited(BatEntity::new, mobEntityBase)
|
||||
.type(EntityType.BAT)
|
||||
.height(0.9f).width(0.5f)
|
||||
.addTranslator(MetadataType.BYTE, BatEntity::setBatFlags)
|
||||
.build();
|
||||
BLAZE = EntityDefinition.inherited(BlazeEntity::new, mobEntityBase)
|
||||
.type(EntityType.BLAZE)
|
||||
.height(1.8f).width(0.6f)
|
||||
.addTranslator(MetadataType.BYTE, BlazeEntity::setBlazeFlags)
|
||||
.build();
|
||||
CAVE_SPIDER = EntityDefinition.inherited(MonsterEntity::new, mobEntityBase)
|
||||
.type(EntityType.CAVE_SPIDER)
|
||||
.height(0.5f).width(0.7f)
|
||||
.build();
|
||||
CREEPER = EntityDefinition.inherited(CreeperEntity::new, mobEntityBase)
|
||||
.type(EntityType.CREEPER)
|
||||
.height(1.7f).width(0.6f)
|
||||
.offset(1.62f)
|
||||
.addTranslator(MetadataType.INT, CreeperEntity::setSwelling)
|
||||
.addTranslator(MetadataType.BOOLEAN, (entity, entityMetadata) -> entity.setFlag(EntityFlag.POWERED, ((BooleanEntityMetadata) entityMetadata).getPrimitiveValue()))
|
||||
.addTranslator(MetadataType.BOOLEAN, CreeperEntity::setIgnited)
|
||||
.build();
|
||||
DOLPHIN = EntityDefinition.inherited(WaterEntity::new, mobEntityBase)
|
||||
.type(EntityType.DOLPHIN)
|
||||
.height(0.6f).width(0.9f)
|
||||
//TODO check
|
||||
.addTranslator(null) // treasure position
|
||||
.addTranslator(null) // "got fish"
|
||||
.addTranslator(null) // "moistness level"
|
||||
.build();
|
||||
ENDERMAN = EntityDefinition.inherited(EndermanEntity::new, mobEntityBase)
|
||||
.type(EntityType.ENDERMAN)
|
||||
.height(2.9f).width(0.6f)
|
||||
.addTranslator(MetadataType.BLOCK_STATE, EndermanEntity::setCarriedBlock)
|
||||
.addTranslator(MetadataType.BOOLEAN, EndermanEntity::setScreaming)
|
||||
.addTranslator(MetadataType.BOOLEAN, EndermanEntity::setAngry)
|
||||
.build();
|
||||
ENDERMITE = EntityDefinition.inherited(MonsterEntity::new, mobEntityBase)
|
||||
.type(EntityType.ENDERMITE)
|
||||
.height(0.3f).width(0.4f)
|
||||
.build();
|
||||
ENDER_DRAGON = EntityDefinition.inherited(EnderDragonEntity::new, mobEntityBase)
|
||||
.type(EntityType.ENDER_DRAGON)
|
||||
.addTranslator(MetadataType.INT, EnderDragonEntity::setPhase)
|
||||
.build();
|
||||
GHAST = EntityDefinition.inherited(GhastEntity::new, mobEntityBase)
|
||||
.type(EntityType.GHAST)
|
||||
.heightAndWidth(4.0f)
|
||||
.addTranslator(MetadataType.BOOLEAN, GhastEntity::setGhastAttacking)
|
||||
.build();
|
||||
GIANT = EntityDefinition.inherited(GiantEntity::new, mobEntityBase)
|
||||
.type(EntityType.GIANT)
|
||||
.height(1.8f).width(1.6f)
|
||||
.offset(1.62f)
|
||||
.identifier("minecraft:zombie")
|
||||
.build();
|
||||
IRON_GOLEM = EntityDefinition.inherited(IronGolemEntity::new, mobEntityBase)
|
||||
.type(EntityType.IRON_GOLEM)
|
||||
.height(2.7f).width(1.4f)
|
||||
.addTranslator(null) // "is player created", which doesn't seem to do anything clientside
|
||||
.build();
|
||||
PHANTOM = EntityDefinition.inherited(PhantomEntity::new, mobEntityBase)
|
||||
.type(EntityType.PHANTOM)
|
||||
.height(0.5f).width(0.9f)
|
||||
.offset(0.6f)
|
||||
.addTranslator(MetadataType.INT, PhantomEntity::setPhantomScale)
|
||||
.build();
|
||||
SILVERFISH = EntityDefinition.inherited(MonsterEntity::new, mobEntityBase)
|
||||
.type(EntityType.SILVERFISH)
|
||||
.height(0.3f).width(0.4f)
|
||||
.build();
|
||||
SHULKER = EntityDefinition.inherited(ShulkerEntity::new, mobEntityBase)
|
||||
.type(EntityType.SHULKER)
|
||||
.heightAndWidth(1f)
|
||||
.addTranslator(MetadataType.DIRECTION, ShulkerEntity::setAttachedFace)
|
||||
.addTranslator(MetadataType.BYTE, ShulkerEntity::setShulkerHeight)
|
||||
.addTranslator(MetadataType.BYTE, ShulkerEntity::setShulkerColor)
|
||||
.build();
|
||||
SKELETON = EntityDefinition.inherited(SkeletonEntity::new, mobEntityBase)
|
||||
.type(EntityType.SKELETON)
|
||||
.height(1.8f).width(0.6f)
|
||||
.offset(1.62f)
|
||||
.addTranslator(MetadataType.BOOLEAN, SkeletonEntity::setConvertingToStray)
|
||||
.build();
|
||||
SNOW_GOLEM = EntityDefinition.inherited(SnowGolemEntity::new, mobEntityBase)
|
||||
.type(EntityType.SNOW_GOLEM)
|
||||
.height(1.9f).width(0.7f)
|
||||
.addTranslator(MetadataType.BYTE, SnowGolemEntity::setSnowGolemFlags)
|
||||
.build();
|
||||
SPIDER = EntityDefinition.inherited(SpiderEntity::new, mobEntityBase)
|
||||
.type(EntityType.SPIDER)
|
||||
.height(0.9f).width(1.4f)
|
||||
.offset(1f)
|
||||
.addTranslator(MetadataType.BYTE, SpiderEntity::setSpiderFlags)
|
||||
.build();
|
||||
SQUID = EntityDefinition.inherited(SquidEntity::new, mobEntityBase)
|
||||
.type(EntityType.SQUID)
|
||||
.heightAndWidth(0.8f)
|
||||
.build();
|
||||
STRAY = EntityDefinition.inherited(AbstractSkeletonEntity::new, mobEntityBase)
|
||||
.type(EntityType.STRAY)
|
||||
.height(1.8f).width(0.6f)
|
||||
.offset(1.62f)
|
||||
.build();
|
||||
VEX = EntityDefinition.inherited(VexEntity::new, mobEntityBase)
|
||||
.type(EntityType.VEX)
|
||||
.height(0.8f).width(0.4f)
|
||||
.addTranslator(MetadataType.BYTE, VexEntity::setVexFlags)
|
||||
.build();
|
||||
WITHER = EntityDefinition.inherited(WitherEntity::new, mobEntityBase)
|
||||
.type(EntityType.WITHER)
|
||||
.height(3.5f).width(0.9f)
|
||||
.addTranslator(MetadataType.INT, WitherEntity::setTarget1)
|
||||
.addTranslator(MetadataType.INT, WitherEntity::setTarget2)
|
||||
.addTranslator(MetadataType.INT, WitherEntity::setTarget3)
|
||||
.addTranslator(MetadataType.INT, WitherEntity::setInvulnerableTicks)
|
||||
.build();
|
||||
WITHER_SKELETON = EntityDefinition.inherited(AbstractSkeletonEntity::new, mobEntityBase)
|
||||
.type(EntityType.WITHER_SKELETON)
|
||||
.height(2.4f).width(0.7f)
|
||||
.build();
|
||||
ZOGLIN = EntityDefinition.inherited(ZoglinEntity::new, mobEntityBase)
|
||||
.type(EntityType.ZOGLIN)
|
||||
.height(1.4f).width(1.3965f)
|
||||
.addTranslator(MetadataType.BOOLEAN, ZoglinEntity::setBaby)
|
||||
.build();
|
||||
ZOMBIE = EntityDefinition.inherited(ZombieEntity::new, mobEntityBase)
|
||||
.type(EntityType.ZOMBIE)
|
||||
.height(1.8f).width(0.6f)
|
||||
.offset(1.62f)
|
||||
.addTranslator(MetadataType.BOOLEAN, ZombieEntity::setZombieBaby)
|
||||
.addTranslator(null) // "set special type", doesn't do anything
|
||||
.addTranslator(MetadataType.BOOLEAN, ZombieEntity::setConvertingToDrowned)
|
||||
.build();
|
||||
ZOMBIE_VILLAGER = EntityDefinition.inherited(ZombieVillagerEntity::new, ZOMBIE)
|
||||
.type(EntityType.ZOMBIE_VILLAGER)
|
||||
.height(1.8f).width(0.6f)
|
||||
.offset(1.62f)
|
||||
.identifier("minecraft:zombie_villager_v2")
|
||||
.addTranslator(MetadataType.BOOLEAN, ZombieVillagerEntity::setTransforming)
|
||||
.addTranslator(MetadataType.VILLAGER_DATA, ZombieVillagerEntity::setZombieVillagerData)
|
||||
.build();
|
||||
ZOMBIFIED_PIGLIN = EntityDefinition.inherited(ZombifiedPiglinEntity::new, ZOMBIE) //TODO test how zombie entity metadata is handled?
|
||||
.type(EntityType.ZOMBIFIED_PIGLIN)
|
||||
.height(1.95f).width(0.6f)
|
||||
.offset(1.62f)
|
||||
.identifier("minecraft:zombie_pigman")
|
||||
.build();
|
||||
|
||||
DROWNED = EntityDefinition.inherited(ZOMBIE.factory(), ZOMBIE)
|
||||
.type(EntityType.DROWNED)
|
||||
.height(1.95f).width(0.6f)
|
||||
.build();
|
||||
HUSK = EntityDefinition.inherited(ZOMBIE.factory(), ZOMBIE)
|
||||
.type(EntityType.HUSK)
|
||||
.build();
|
||||
|
||||
GUARDIAN = EntityDefinition.inherited(GuardianEntity::new, mobEntityBase)
|
||||
.type(EntityType.GUARDIAN)
|
||||
.heightAndWidth(0.85f)
|
||||
.addTranslator(null) // Moving //TODO
|
||||
.addTranslator(MetadataType.INT, GuardianEntity::setGuardianTarget)
|
||||
.build();
|
||||
ELDER_GUARDIAN = EntityDefinition.inherited(ElderGuardianEntity::new, GUARDIAN)
|
||||
.type(EntityType.ELDER_GUARDIAN)
|
||||
.heightAndWidth(1.9975f)
|
||||
.build();
|
||||
|
||||
SLIME = EntityDefinition.inherited(SlimeEntity::new, mobEntityBase)
|
||||
.type(EntityType.SLIME)
|
||||
.heightAndWidth(0.51f)
|
||||
.addTranslator(MetadataType.INT, SlimeEntity::setScale)
|
||||
.build();
|
||||
MAGMA_CUBE = EntityDefinition.inherited(MagmaCubeEntity::new, SLIME)
|
||||
.type(EntityType.MAGMA_CUBE)
|
||||
.build();
|
||||
|
||||
EntityDefinition<AbstractFishEntity> abstractFishEntityBase = EntityDefinition.inherited(AbstractFishEntity::new, mobEntityBase)
|
||||
.addTranslator(null) // From bucket
|
||||
.build();
|
||||
COD = EntityDefinition.inherited(abstractFishEntityBase.factory(), abstractFishEntityBase)
|
||||
.type(EntityType.COD)
|
||||
.height(0.25f).width(0.5f)
|
||||
.build();
|
||||
PUFFERFISH = EntityDefinition.inherited(PufferFishEntity::new, abstractFishEntityBase)
|
||||
.type(EntityType.PUFFERFISH)
|
||||
.heightAndWidth(0.7f)
|
||||
.addTranslator(MetadataType.INT, PufferFishEntity::setPufferfishSize)
|
||||
.build();
|
||||
SALMON = EntityDefinition.inherited(abstractFishEntityBase.factory(), abstractFishEntityBase)
|
||||
.type(EntityType.SALMON)
|
||||
.height(0.5f).width(0.7f)
|
||||
.build();
|
||||
TROPICAL_FISH = EntityDefinition.inherited(TropicalFishEntity::new, abstractFishEntityBase)
|
||||
.type(EntityType.TROPICAL_FISH)
|
||||
.heightAndWidth(0.6f)
|
||||
.identifier("minecraft:tropicalfish")
|
||||
.addTranslator(MetadataType.INT, TropicalFishEntity::setFishVariant)
|
||||
.build();
|
||||
|
||||
EntityDefinition<BasePiglinEntity> abstractPiglinEntityBase = EntityDefinition.inherited(BasePiglinEntity::new, mobEntityBase)
|
||||
.addTranslator(MetadataType.BOOLEAN, BasePiglinEntity::setImmuneToZombification)
|
||||
.build();
|
||||
PIGLIN = EntityDefinition.inherited(PiglinEntity::new, abstractPiglinEntityBase)
|
||||
.type(EntityType.PIGLIN)
|
||||
.height(1.95f).width(0.6f)
|
||||
.addTranslator(MetadataType.BOOLEAN, PiglinEntity::setBaby)
|
||||
.addTranslator(MetadataType.BOOLEAN, PiglinEntity::setChargingCrossbow)
|
||||
.addTranslator(MetadataType.BOOLEAN, PiglinEntity::setDancing)
|
||||
.build();
|
||||
PIGLIN_BRUTE = EntityDefinition.inherited(abstractPiglinEntityBase.factory(), abstractPiglinEntityBase)
|
||||
.type(EntityType.PIGLIN_BRUTE)
|
||||
.height(1.95f).width(0.6f)
|
||||
.build();
|
||||
|
||||
GLOW_SQUID = EntityDefinition.inherited(GlowSquidEntity::new, SQUID)
|
||||
.type(EntityType.GLOW_SQUID)
|
||||
.addTranslator(null) // Set dark ticks remaining, possible TODO
|
||||
.build();
|
||||
|
||||
EntityDefinition<RaidParticipantEntity> raidParticipantEntityBase = EntityDefinition.inherited(RaidParticipantEntity::new, mobEntityBase)
|
||||
.addTranslator(null) // Celebrating //TODO
|
||||
.build();
|
||||
EntityDefinition<SpellcasterIllagerEntity> spellcasterEntityBase = EntityDefinition.inherited(SpellcasterIllagerEntity::new, raidParticipantEntityBase)
|
||||
.addTranslator(MetadataType.BYTE, SpellcasterIllagerEntity::setSpellType)
|
||||
.build();
|
||||
EVOKER = EntityDefinition.inherited(spellcasterEntityBase.factory(), spellcasterEntityBase)
|
||||
.type(EntityType.EVOKER)
|
||||
.height(1.95f).width(0.6f)
|
||||
.identifier("minecraft:evocation_illager")
|
||||
.build();
|
||||
ILLUSIONER = EntityDefinition.inherited(spellcasterEntityBase.factory(), spellcasterEntityBase)
|
||||
.type(EntityType.ILLUSIONER)
|
||||
.height(1.95f).width(0.6f)
|
||||
.identifier("minecraft:evocation_illager")
|
||||
.build();
|
||||
PILLAGER = EntityDefinition.inherited(PillagerEntity::new, raidParticipantEntityBase)
|
||||
.type(EntityType.PILLAGER)
|
||||
.height(1.8f).width(0.6f)
|
||||
.offset(1.62f)
|
||||
.addTranslator(null) // Charging; doesn't have an equivalent on Bedrock //TODO check
|
||||
.build();
|
||||
RAVAGER = EntityDefinition.inherited(raidParticipantEntityBase.factory(), raidParticipantEntityBase)
|
||||
.type(EntityType.RAVAGER)
|
||||
.height(1.9f).width(1.2f)
|
||||
.build();
|
||||
VINDICATOR = EntityDefinition.inherited(VindicatorEntity::new, raidParticipantEntityBase)
|
||||
.type(EntityType.VINDICATOR)
|
||||
.height(1.8f).width(0.6f)
|
||||
.offset(1.62f)
|
||||
.build();
|
||||
WITCH = EntityDefinition.inherited(raidParticipantEntityBase.factory(), raidParticipantEntityBase)
|
||||
.type(EntityType.WITCH)
|
||||
.height(1.8f).width(0.6f)
|
||||
.offset(1.62f)
|
||||
.addTranslator(null) // Using item
|
||||
.build();
|
||||
}
|
||||
|
||||
EntityDefinition<AgeableEntity> ageableEntityBase = EntityDefinition.inherited(AgeableEntity::new, mobEntityBase)
|
||||
.addTranslator(MetadataType.BOOLEAN, AgeableEntity::setBaby)
|
||||
.build();
|
||||
|
||||
// Extends ageable
|
||||
{
|
||||
AXOLOTL = EntityDefinition.inherited(AxolotlEntity::new, ageableEntityBase)
|
||||
.type(EntityType.AXOLOTL)
|
||||
.height(0.42f).width(0.7f)
|
||||
.addTranslator(MetadataType.INT, AxolotlEntity::setVariant)
|
||||
.addTranslator(MetadataType.BOOLEAN, AxolotlEntity::setPlayingDead)
|
||||
.addTranslator(null) // From bucket
|
||||
.build();
|
||||
BEE = EntityDefinition.inherited(BeeEntity::new, ageableEntityBase)
|
||||
.type(EntityType.BEE)
|
||||
.heightAndWidth(0.6f)
|
||||
.addTranslator(MetadataType.BYTE, BeeEntity::setBeeFlags)
|
||||
.addTranslator(MetadataType.INT, BeeEntity::setAngerTime)
|
||||
.build();
|
||||
CHICKEN = EntityDefinition.inherited(ChickenEntity::new, ageableEntityBase)
|
||||
.type(EntityType.CHICKEN)
|
||||
.height(0.7f).width(0.4f)
|
||||
.build();
|
||||
COW = EntityDefinition.inherited(AnimalEntity::new, ageableEntityBase)
|
||||
.type(EntityType.COW)
|
||||
.height(1.4f).width(0.9f)
|
||||
.build();
|
||||
FOX = EntityDefinition.inherited(FoxEntity::new, ageableEntityBase)
|
||||
.type(EntityType.FOX)
|
||||
.height(0.5f).width(1.25f)
|
||||
.addTranslator(MetadataType.INT, FoxEntity::setFoxVariant)
|
||||
.addTranslator(MetadataType.BYTE, FoxEntity::setFoxFlags)
|
||||
.build();
|
||||
HOGLIN = EntityDefinition.inherited(HoglinEntity::new, ageableEntityBase)
|
||||
.type(EntityType.HOGLIN)
|
||||
.height(1.4f).width(1.3965f)
|
||||
.addTranslator(MetadataType.BOOLEAN, HoglinEntity::setImmuneToZombification)
|
||||
.build();
|
||||
GOAT = EntityDefinition.inherited(GoatEntity::new, ageableEntityBase)
|
||||
.type(EntityType.GOAT)
|
||||
.height(1.3f).width(0.9f)
|
||||
.addTranslator(MetadataType.BOOLEAN, GoatEntity::setScreamer)
|
||||
.build();
|
||||
MOOSHROOM = EntityDefinition.inherited(MooshroomEntity::new, ageableEntityBase) // TODO remove class
|
||||
.type(EntityType.MOOSHROOM)
|
||||
.height(1.4f).width(0.9f)
|
||||
.addTranslator(MetadataType.STRING, (entity, entityMetadata) -> entity.getDirtyMetadata().put(EntityData.VARIANT, entityMetadata.getValue().equals("brown") ? 1 : 0))
|
||||
.build();
|
||||
OCELOT = EntityDefinition.inherited(OcelotEntity::new, ageableEntityBase)
|
||||
.type(EntityType.OCELOT)
|
||||
.height(0.35f).width(0.3f)
|
||||
.addTranslator(MetadataType.BOOLEAN, (ocelotEntity, entityMetadata) -> ocelotEntity.setFlag(EntityFlag.TRUSTING, ((BooleanEntityMetadata) entityMetadata).getPrimitiveValue()))
|
||||
.build();
|
||||
PANDA = EntityDefinition.inherited(PandaEntity::new, ageableEntityBase)
|
||||
.type(EntityType.PANDA)
|
||||
.height(1.25f).width(1.125f)
|
||||
.addTranslator(null) // Unhappy counter
|
||||
.addTranslator(null) // Sneeze counter
|
||||
.addTranslator(MetadataType.INT, PandaEntity::setEatingCounter)
|
||||
.addTranslator(MetadataType.BYTE, PandaEntity::setMainGene)
|
||||
.addTranslator(MetadataType.BYTE, PandaEntity::setHiddenGene)
|
||||
.addTranslator(MetadataType.BYTE, PandaEntity::setPandaFlags)
|
||||
.build();
|
||||
PIG = EntityDefinition.inherited(PigEntity::new, ageableEntityBase)
|
||||
.type(EntityType.PIG)
|
||||
.heightAndWidth(0.9f)
|
||||
.addTranslator(MetadataType.BOOLEAN, (pigEntity, entityMetadata) -> pigEntity.setFlag(EntityFlag.SADDLED, ((BooleanEntityMetadata) entityMetadata).getPrimitiveValue()))
|
||||
.addTranslator(null) // Boost time
|
||||
.build();
|
||||
POLAR_BEAR = EntityDefinition.inherited(PolarBearEntity::new, ageableEntityBase)
|
||||
.type(EntityType.POLAR_BEAR)
|
||||
.height(1.4f).width(1.3f)
|
||||
.addTranslator(MetadataType.BOOLEAN, (entity, entityMetadata) -> entity.setFlag(EntityFlag.STANDING, ((BooleanEntityMetadata) entityMetadata).getPrimitiveValue()))
|
||||
.build();
|
||||
RABBIT = EntityDefinition.inherited(RabbitEntity::new, ageableEntityBase)
|
||||
.type(EntityType.RABBIT)
|
||||
.height(0.5f).width(0.4f)
|
||||
.addTranslator(MetadataType.INT, RabbitEntity::setRabbitVariant)
|
||||
.build();
|
||||
SHEEP = EntityDefinition.inherited(SheepEntity::new, ageableEntityBase)
|
||||
.type(EntityType.SHEEP)
|
||||
.heightAndWidth(0.9f)
|
||||
.addTranslator(MetadataType.BYTE, SheepEntity::setSheepFlags)
|
||||
.build();
|
||||
STRIDER = EntityDefinition.inherited(StriderEntity::new, ageableEntityBase)
|
||||
.type(EntityType.STRIDER)
|
||||
.height(1.7f).width(0.9f)
|
||||
.addTranslator(null) // Boost time
|
||||
.addTranslator(MetadataType.BOOLEAN, StriderEntity::setCold)
|
||||
.addTranslator(MetadataType.BOOLEAN, StriderEntity::setSaddled)
|
||||
.build();
|
||||
TURTLE = EntityDefinition.inherited(TurtleEntity::new, ageableEntityBase)
|
||||
.type(EntityType.TURTLE)
|
||||
.height(0.4f).width(1.2f)
|
||||
.addTranslator(null) // Home position
|
||||
.addTranslator(MetadataType.BOOLEAN, TurtleEntity::setPregnant)
|
||||
.addTranslator(MetadataType.BOOLEAN, TurtleEntity::setLayingEgg)
|
||||
.addTranslator(null) // Travel position
|
||||
.addTranslator(null) // Going home
|
||||
.addTranslator(null) // Travelling
|
||||
.build();
|
||||
|
||||
EntityDefinition<AbstractMerchantEntity> abstractVillagerEntityBase = EntityDefinition.inherited(AbstractMerchantEntity::new, ageableEntityBase)
|
||||
.addTranslator(null) // Unhappy ticks
|
||||
.build();
|
||||
VILLAGER = EntityDefinition.inherited(VillagerEntity::new, abstractVillagerEntityBase)
|
||||
.type(EntityType.VILLAGER)
|
||||
.height(1.8f).width(0.6f)
|
||||
.offset(1.62f)
|
||||
.identifier("minecraft:villager_v2")
|
||||
.addTranslator(MetadataType.VILLAGER_DATA, VillagerEntity::setVillagerData)
|
||||
.build();
|
||||
WANDERING_TRADER = EntityDefinition.inherited(abstractVillagerEntityBase.factory(), abstractVillagerEntityBase)
|
||||
.type(EntityType.WANDERING_TRADER)
|
||||
.height(1.8f).width(0.6f)
|
||||
.offset(1.62f)
|
||||
.build();
|
||||
}
|
||||
|
||||
// Horses
|
||||
{
|
||||
EntityDefinition<AbstractHorseEntity> abstractHorseEntityBase = EntityDefinition.inherited(AbstractHorseEntity::new, ageableEntityBase)
|
||||
.addTranslator(MetadataType.BYTE, AbstractHorseEntity::setHorseFlags)
|
||||
.addTranslator(null) // UUID of owner
|
||||
.build();
|
||||
HORSE = EntityDefinition.inherited(HorseEntity::new, abstractHorseEntityBase)
|
||||
.type(EntityType.HORSE)
|
||||
.height(1.6f).width(1.3965f)
|
||||
.addTranslator(MetadataType.INT, HorseEntity::setHorseVariant)
|
||||
.build();
|
||||
SKELETON_HORSE = EntityDefinition.inherited(abstractHorseEntityBase.factory(), abstractHorseEntityBase)
|
||||
.type(EntityType.SKELETON_HORSE)
|
||||
.height(1.6f).width(1.3965f)
|
||||
.build();
|
||||
ZOMBIE_HORSE = EntityDefinition.inherited(abstractHorseEntityBase.factory(), abstractHorseEntityBase)
|
||||
.type(EntityType.ZOMBIE_HORSE)
|
||||
.height(1.6f).width(1.3965f)
|
||||
.build();
|
||||
EntityDefinition<ChestedHorseEntity> chestedHorseEntityBase = EntityDefinition.inherited(ChestedHorseEntity::new, abstractHorseEntityBase)
|
||||
.addTranslator(MetadataType.BOOLEAN, (horseEntity, entityMetadata) -> horseEntity.setFlag(EntityFlag.CHESTED, ((BooleanEntityMetadata) entityMetadata).getPrimitiveValue()))
|
||||
.build();
|
||||
DONKEY = EntityDefinition.inherited(chestedHorseEntityBase.factory(), chestedHorseEntityBase)
|
||||
.type(EntityType.DONKEY)
|
||||
.height(1.6f).width(1.3965f)
|
||||
.build();
|
||||
MULE = EntityDefinition.inherited(chestedHorseEntityBase.factory(), chestedHorseEntityBase)
|
||||
.type(EntityType.MULE)
|
||||
.height(1.6f).width(1.3965f)
|
||||
.build();
|
||||
LLAMA = EntityDefinition.inherited(LlamaEntity::new, chestedHorseEntityBase)
|
||||
.type(EntityType.LLAMA)
|
||||
.height(1.87f).width(0.9f)
|
||||
.addTranslator(MetadataType.INT, (entity, entityMetadata) -> entity.getDirtyMetadata().put(EntityData.STRENGTH, entityMetadata.getValue()))
|
||||
.addTranslator(MetadataType.INT, LlamaEntity::setCarpetedColor)
|
||||
.addTranslator(MetadataType.INT, (entity, entityMetadata) -> entity.getDirtyMetadata().put(EntityData.VARIANT, entityMetadata.getValue()))
|
||||
.build();
|
||||
TRADER_LLAMA = EntityDefinition.inherited(TraderLlamaEntity::new, LLAMA)
|
||||
.type(EntityType.TRADER_LLAMA)
|
||||
.identifier("minecraft:llama")
|
||||
.build();
|
||||
}
|
||||
|
||||
EntityDefinition<TameableEntity> tameableEntityBase = EntityDefinition.inherited(TameableEntity::new, ageableEntityBase)
|
||||
.addTranslator(MetadataType.BYTE, TameableEntity::setTameableFlags)
|
||||
.addTranslator(MetadataType.OPTIONAL_UUID, TameableEntity::setOwner)
|
||||
.build();
|
||||
CAT = EntityDefinition.inherited(CatEntity::new, tameableEntityBase)
|
||||
.type(EntityType.CAT)
|
||||
.height(0.35f).width(0.3f)
|
||||
.addTranslator(MetadataType.INT, CatEntity::setCatVariant)
|
||||
.addTranslator(MetadataType.BOOLEAN, CatEntity::setResting)
|
||||
.addTranslator(null) // "resting state one" //TODO
|
||||
.addTranslator(MetadataType.INT, CatEntity::setCollarColor)
|
||||
.build();
|
||||
PARROT = EntityDefinition.inherited(ParrotEntity::new, tameableEntityBase)
|
||||
.type(EntityType.PARROT)
|
||||
.height(0.9f).width(0.5f)
|
||||
.addTranslator(MetadataType.INT, (parrotEntity, entityMetadata) -> parrotEntity.getDirtyMetadata().put(EntityData.VARIANT, entityMetadata.getValue())) // Parrot color
|
||||
.build();
|
||||
WOLF = EntityDefinition.inherited(WolfEntity::new, tameableEntityBase)
|
||||
.type(EntityType.WOLF)
|
||||
.height(0.85f).width(0.6f)
|
||||
// "Begging" on wiki.vg, "Interested" in Nukkit - the tilt of the head
|
||||
.addTranslator(MetadataType.BOOLEAN, (wolfEntity, entityMetadata) -> wolfEntity.setFlag(EntityFlag.INTERESTED, ((BooleanEntityMetadata) entityMetadata).getPrimitiveValue()))
|
||||
.addTranslator(MetadataType.INT, WolfEntity::setCollarColor)
|
||||
.addTranslator(MetadataType.INT, WolfEntity::setWolfAngerTime)
|
||||
.build();
|
||||
|
||||
// As of 1.18 these don't track entity data at all
|
||||
ENDER_DRAGON_PART = EntityDefinition.<EnderDragonPartEntity>builder(null)
|
||||
.identifier("minecraft:armor_stand") // Emulated
|
||||
.build();
|
||||
|
||||
Registries.JAVA_ENTITY_IDENTIFIERS.get().put("minecraft:marker", null); // We don't need an entity definition for this as it is never sent over the network
|
||||
}
|
||||
|
||||
public static void init() {
|
||||
// no-op
|
||||
}
|
||||
|
||||
private EntityDefinitions() {
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,39 @@
|
|||
/*
|
||||
* Copyright (c) 2019-2021 GeyserMC. http://geysermc.org
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*
|
||||
* @author GeyserMC
|
||||
* @link https://github.com/GeyserMC/Geyser
|
||||
*/
|
||||
|
||||
package org.geysermc.connector.entity;
|
||||
|
||||
import com.github.steveice10.mc.protocol.data.game.entity.metadata.EntityMetadata;
|
||||
import com.github.steveice10.mc.protocol.data.game.entity.metadata.MetadataType;
|
||||
|
||||
import java.util.function.BiConsumer;
|
||||
|
||||
/**
|
||||
* Translates a given Java {@link EntityMetadata} into a similar/same construct for Bedrock
|
||||
*/
|
||||
public record EntityMetadataTranslator<E extends Entity, T, EM extends EntityMetadata<T, ? extends MetadataType<T>>>(
|
||||
MetadataType<T> acceptedType,
|
||||
BiConsumer<E, EM> translateFunction) {
|
||||
}
|
||||
|
|
@ -0,0 +1,47 @@
|
|||
/*
|
||||
* Copyright (c) 2019-2021 GeyserMC. http://geysermc.org
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*
|
||||
* @author GeyserMC
|
||||
* @link https://github.com/GeyserMC/Geyser
|
||||
*/
|
||||
|
||||
package org.geysermc.connector.entity;
|
||||
|
||||
import com.nukkitx.math.vector.Vector3f;
|
||||
import com.nukkitx.protocol.bedrock.data.entity.EntityData;
|
||||
import org.geysermc.connector.network.session.GeyserSession;
|
||||
|
||||
public class ExpOrbEntity extends Entity {
|
||||
|
||||
private final int amount;
|
||||
|
||||
public ExpOrbEntity(GeyserSession session, int amount, long entityId, long geyserId, Vector3f position) {
|
||||
super(session, entityId, geyserId, null, EntityDefinitions.EXPERIENCE_ORB, position, Vector3f.ZERO, 0, 0, 0);
|
||||
|
||||
this.amount = amount;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void initializeMetadata() {
|
||||
super.initializeMetadata();
|
||||
this.dirtyMetadata.put(EntityData.EXPERIENCE_VALUE, amount);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,56 @@
|
|||
/*
|
||||
* Copyright (c) 2019-2021 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.type.BooleanEntityMetadata;
|
||||
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.network.session.GeyserSession;
|
||||
|
||||
import java.util.UUID;
|
||||
|
||||
public class FallingBlockEntity extends Entity {
|
||||
private final int javaId;
|
||||
|
||||
public FallingBlockEntity(GeyserSession session, long entityId, long geyserId, UUID uuid, Vector3f position, Vector3f motion, float yaw, float pitch, int javaId) {
|
||||
super(session, entityId, geyserId, uuid, EntityDefinitions.FALLING_BLOCK, position, motion, yaw, pitch, 0f);
|
||||
this.javaId = javaId;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void initializeMetadata() {
|
||||
super.initializeMetadata();
|
||||
this.dirtyMetadata.put(EntityData.VARIANT, session.getBlockMappings().getBedrockBlockId(javaId));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setGravity(BooleanEntityMetadata entityMetadata) {
|
||||
super.setGravity(entityMetadata);
|
||||
// Set the NO_AI flag based on the no gravity flag to prevent movement
|
||||
setFlag(EntityFlag.NO_AI, entityMetadata.getPrimitiveValue());
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,160 @@
|
|||
/*
|
||||
* Copyright (c) 2019-2021 GeyserMC. http://geysermc.org
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*
|
||||
* @author GeyserMC
|
||||
* @link https://github.com/GeyserMC/Geyser
|
||||
*/
|
||||
|
||||
package org.geysermc.connector.entity;
|
||||
|
||||
import com.github.steveice10.mc.protocol.data.game.entity.metadata.EntityMetadata;
|
||||
import com.github.steveice10.mc.protocol.data.game.entity.metadata.ItemStack;
|
||||
import com.github.steveice10.opennbt.tag.builtin.CompoundTag;
|
||||
import com.github.steveice10.opennbt.tag.builtin.ListTag;
|
||||
import com.github.steveice10.opennbt.tag.builtin.Tag;
|
||||
import com.nukkitx.math.vector.Vector3f;
|
||||
import com.nukkitx.nbt.NbtMap;
|
||||
import com.nukkitx.nbt.NbtMapBuilder;
|
||||
import com.nukkitx.nbt.NbtType;
|
||||
import com.nukkitx.protocol.bedrock.data.entity.EntityData;
|
||||
import com.nukkitx.protocol.bedrock.packet.SetEntityMotionPacket;
|
||||
import org.geysermc.connector.entity.player.PlayerEntity;
|
||||
import org.geysermc.connector.network.session.GeyserSession;
|
||||
import org.geysermc.connector.utils.FireworkColor;
|
||||
import org.geysermc.connector.utils.MathUtils;
|
||||
import org.geysermc.floodgate.util.DeviceOs;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.OptionalInt;
|
||||
import java.util.UUID;
|
||||
|
||||
public class FireworkEntity extends Entity {
|
||||
|
||||
public FireworkEntity(GeyserSession session, long entityId, long geyserId, UUID uuid, EntityDefinition<?> definition, Vector3f position, Vector3f motion, float yaw, float pitch, float headYaw) {
|
||||
super(session, entityId, geyserId, uuid, definition, position, motion, yaw, pitch, headYaw);
|
||||
}
|
||||
|
||||
public void setFireworkItem(EntityMetadata<ItemStack, ?> entityMetadata) {
|
||||
ItemStack item = entityMetadata.getValue();
|
||||
if (item == null) {
|
||||
return;
|
||||
}
|
||||
CompoundTag tag = item.getNbt();
|
||||
|
||||
if (tag == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
// TODO: Remove once Mojang fixes bugs with fireworks crashing clients on these specific devices.
|
||||
// https://bugs.mojang.com/browse/MCPE-89115
|
||||
if (session.getClientData().getDeviceOs() == DeviceOs.XBOX
|
||||
|| session.getClientData().getDeviceOs() == DeviceOs.PS4) {
|
||||
return;
|
||||
}
|
||||
|
||||
CompoundTag fireworks = tag.get("Fireworks");
|
||||
if (fireworks == null) {
|
||||
// Thank you Mineplex very cool
|
||||
return;
|
||||
}
|
||||
|
||||
NbtMapBuilder fireworksBuilder = NbtMap.builder();
|
||||
if (fireworks.get("Flight") != null) {
|
||||
fireworksBuilder.putByte("Flight", MathUtils.getNbtByte(fireworks.get("Flight").getValue()));
|
||||
}
|
||||
|
||||
List<NbtMap> explosions = new ArrayList<>();
|
||||
if (fireworks.get("Explosions") != null) {
|
||||
for (Tag effect : ((ListTag) fireworks.get("Explosions")).getValue()) {
|
||||
CompoundTag effectData = (CompoundTag) effect;
|
||||
NbtMapBuilder effectBuilder = NbtMap.builder();
|
||||
|
||||
if (effectData.get("Type") != null) {
|
||||
effectBuilder.putByte("FireworkType", MathUtils.getNbtByte(effectData.get("Type").getValue()));
|
||||
}
|
||||
|
||||
if (effectData.get("Colors") != null) {
|
||||
int[] oldColors = (int[]) effectData.get("Colors").getValue();
|
||||
byte[] colors = new byte[oldColors.length];
|
||||
|
||||
int i = 0;
|
||||
for (int color : oldColors) {
|
||||
colors[i++] = FireworkColor.fromJavaRGB(color);
|
||||
}
|
||||
|
||||
effectBuilder.putByteArray("FireworkColor", colors);
|
||||
}
|
||||
|
||||
if (effectData.get("FadeColors") != null) {
|
||||
int[] oldColors = (int[]) effectData.get("FadeColors").getValue();
|
||||
byte[] colors = new byte[oldColors.length];
|
||||
|
||||
int i = 0;
|
||||
for (int color : oldColors) {
|
||||
colors[i++] = FireworkColor.fromJavaRGB(color);
|
||||
}
|
||||
|
||||
effectBuilder.putByteArray("FireworkFade", colors);
|
||||
}
|
||||
|
||||
if (effectData.get("Trail") != null) {
|
||||
effectBuilder.putByte("FireworkTrail", MathUtils.getNbtByte(effectData.get("Trail").getValue()));
|
||||
}
|
||||
|
||||
if (effectData.get("Flicker") != null) {
|
||||
effectBuilder.putByte("FireworkFlicker", MathUtils.getNbtByte(effectData.get("Flicker").getValue()));
|
||||
}
|
||||
|
||||
explosions.add(effectBuilder.build());
|
||||
}
|
||||
}
|
||||
|
||||
fireworksBuilder.putList("Explosions", NbtType.COMPOUND, explosions);
|
||||
|
||||
NbtMapBuilder builder = NbtMap.builder();
|
||||
builder.put("Fireworks", fireworksBuilder.build());
|
||||
dirtyMetadata.put(EntityData.DISPLAY_ITEM, builder.build());
|
||||
}
|
||||
|
||||
public void setPlayerGliding(EntityMetadata<OptionalInt, ?> entityMetadata) {
|
||||
OptionalInt optional = entityMetadata.getValue();
|
||||
// Checks if the firework has an entity ID (used when a player is gliding)
|
||||
// and checks to make sure the player that is gliding is the one getting sent the packet
|
||||
// or else every player near the gliding player will boost too.
|
||||
if (optional.isPresent() && optional.getAsInt() == session.getPlayerEntity().getEntityId()) {
|
||||
PlayerEntity entity = session.getPlayerEntity();
|
||||
float yaw = entity.getYaw();
|
||||
float pitch = entity.getPitch();
|
||||
// Uses math from NukkitX
|
||||
entity.setMotion(Vector3f.from(
|
||||
-Math.sin(Math.toRadians(yaw)) * Math.cos(Math.toRadians(pitch)) * 2,
|
||||
-Math.sin(Math.toRadians(pitch)) * 2,
|
||||
Math.cos(Math.toRadians(yaw)) * Math.cos(Math.toRadians(pitch)) * 2));
|
||||
// Need to update the EntityMotionPacket or else the player won't boost
|
||||
SetEntityMotionPacket entityMotionPacket = new SetEntityMotionPacket();
|
||||
entityMotionPacket.setRuntimeEntityId(entity.getGeyserId());
|
||||
entityMotionPacket.setMotion(entity.getMotion());
|
||||
|
||||
session.sendUpstreamPacket(entityMotionPacket);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,192 @@
|
|||
/*
|
||||
* Copyright (c) 2019-2021 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.type.IntEntityMetadata;
|
||||
import com.nukkitx.math.vector.Vector3f;
|
||||
import com.nukkitx.protocol.bedrock.data.entity.EntityData;
|
||||
import com.nukkitx.protocol.bedrock.data.entity.EntityFlag;
|
||||
import com.nukkitx.protocol.bedrock.packet.PlaySoundPacket;
|
||||
import lombok.Getter;
|
||||
import org.geysermc.connector.entity.player.PlayerEntity;
|
||||
import org.geysermc.connector.network.session.GeyserSession;
|
||||
import org.geysermc.connector.network.translators.collision.BoundingBox;
|
||||
import org.geysermc.connector.network.translators.collision.translators.BlockCollision;
|
||||
import org.geysermc.connector.network.translators.world.block.BlockStateValues;
|
||||
import org.geysermc.connector.registry.BlockRegistries;
|
||||
import org.geysermc.connector.utils.BlockPositionIterator;
|
||||
import org.geysermc.connector.utils.BlockUtils;
|
||||
|
||||
import java.util.UUID;
|
||||
import java.util.concurrent.ThreadLocalRandom;
|
||||
|
||||
public class FishingHookEntity extends ThrowableEntity {
|
||||
|
||||
private boolean hooked = false;
|
||||
private boolean inWater = false;
|
||||
|
||||
@Getter
|
||||
private final boolean isOwnerSessionPlayer;
|
||||
@Getter
|
||||
private long bedrockTargetId;
|
||||
|
||||
private final BoundingBox boundingBox;
|
||||
|
||||
public FishingHookEntity(GeyserSession session, long entityId, long geyserId, UUID uuid, Vector3f position, Vector3f motion, float yaw, float pitch, PlayerEntity owner) {
|
||||
super(session, entityId, geyserId, uuid, EntityDefinitions.FISHING_BOBBER, position, motion, yaw, pitch, 0f);
|
||||
|
||||
this.boundingBox = new BoundingBox(0.125, 0.125, 0.125, 0.25, 0.25, 0.25);
|
||||
|
||||
// In Java, the splash sound depends on the entity's velocity, but in Bedrock the volume doesn't change.
|
||||
// This splash can be confused with the sound from catching a fish. This silences the splash from Bedrock,
|
||||
// so that it can be handled by moveAbsoluteImmediate.
|
||||
setBoundingBoxHeight(128);
|
||||
|
||||
isOwnerSessionPlayer = owner.getGeyserId() == session.getPlayerEntity().getGeyserId();
|
||||
this.dirtyMetadata.put(EntityData.OWNER_EID, owner.getGeyserId());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void spawnEntity() {
|
||||
|
||||
super.spawnEntity();
|
||||
}
|
||||
|
||||
public void setHookedEntity(IntEntityMetadata entityMetadata) {
|
||||
int hookedEntityId = entityMetadata.getPrimitiveValue() - 1;
|
||||
Entity entity;
|
||||
if (session.getPlayerEntity().getEntityId() == hookedEntityId) {
|
||||
entity = session.getPlayerEntity();
|
||||
} else {
|
||||
entity = session.getEntityCache().getEntityByJavaId(hookedEntityId);
|
||||
}
|
||||
|
||||
if (entity != null) {
|
||||
bedrockTargetId = entity.getGeyserId();
|
||||
dirtyMetadata.put(EntityData.TARGET_EID, bedrockTargetId);
|
||||
hooked = true;
|
||||
} else {
|
||||
hooked = false;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void moveAbsoluteImmediate(Vector3f position, float yaw, float pitch, float headYaw, boolean isOnGround, boolean teleported) {
|
||||
boundingBox.setMiddleX(position.getX());
|
||||
boundingBox.setMiddleY(position.getY() + boundingBox.getSizeY() / 2);
|
||||
boundingBox.setMiddleZ(position.getZ());
|
||||
|
||||
boolean touchingWater = false;
|
||||
boolean collided = false;
|
||||
for (BlockPositionIterator iter = session.getCollisionManager().collidableBlocksIterator(boundingBox); iter.hasNext(); iter.next()) {
|
||||
int blockID = session.getConnector().getWorldManager().getBlockAt(session, iter.getX(), iter.getY(), iter.getZ());
|
||||
BlockCollision blockCollision = BlockUtils.getCollision(blockID);
|
||||
if (blockCollision != null) {
|
||||
if (blockCollision.checkIntersection(iter.getX(), iter.getY(), iter.getZ(), boundingBox)) {
|
||||
// TODO Push bounding box out of collision to improve movement
|
||||
collided = true;
|
||||
}
|
||||
}
|
||||
|
||||
int waterLevel = BlockStateValues.getWaterLevel(blockID);
|
||||
if (BlockRegistries.WATERLOGGED.get().contains(blockID)) {
|
||||
waterLevel = 0;
|
||||
}
|
||||
if (waterLevel >= 0) {
|
||||
double waterMaxY = iter.getY() + 1 - (waterLevel + 1) / 9.0;
|
||||
// Falling water is a full block
|
||||
if (waterLevel >= 8) {
|
||||
waterMaxY = iter.getY() + 1;
|
||||
}
|
||||
if (position.getY() <= waterMaxY) {
|
||||
touchingWater = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!inWater && touchingWater) {
|
||||
sendSplashSound(session);
|
||||
}
|
||||
inWater = touchingWater;
|
||||
|
||||
if (!collided) {
|
||||
super.moveAbsoluteImmediate(position, yaw, pitch, headYaw, isOnGround, teleported);
|
||||
} else {
|
||||
super.moveAbsoluteImmediate(this.position, yaw, pitch, headYaw, true, true);
|
||||
}
|
||||
}
|
||||
|
||||
private void sendSplashSound(GeyserSession session) {
|
||||
if (!getFlag(EntityFlag.SILENT)) {
|
||||
float volume = (float) (0.2f * Math.sqrt(0.2 * (motion.getX() * motion.getX() + motion.getZ() * motion.getZ()) + motion.getY() * motion.getY()));
|
||||
if (volume > 1) {
|
||||
volume = 1;
|
||||
}
|
||||
PlaySoundPacket playSoundPacket = new PlaySoundPacket();
|
||||
playSoundPacket.setSound("random.splash");
|
||||
playSoundPacket.setPosition(position);
|
||||
playSoundPacket.setVolume(volume);
|
||||
playSoundPacket.setPitch(1f + ThreadLocalRandom.current().nextFloat() * 0.3f);
|
||||
session.sendUpstreamPacket(playSoundPacket);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void tick() {
|
||||
if (hooked || !isInAir() && !isInWater() || isOnGround()) {
|
||||
motion = Vector3f.ZERO;
|
||||
return;
|
||||
}
|
||||
float gravity = getGravity();
|
||||
motion = motion.down(gravity);
|
||||
|
||||
moveAbsoluteImmediate(position.add(motion), yaw, pitch, headYaw, onGround, false);
|
||||
|
||||
float drag = getDrag();
|
||||
motion = motion.mul(drag);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected float getGravity() {
|
||||
if (!isInWater() && !onGround) {
|
||||
return 0.03f;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return true if this entity is currently in air.
|
||||
*/
|
||||
protected boolean isInAir() {
|
||||
int block = session.getConnector().getWorldManager().getBlockAt(session, position.toInt());
|
||||
return block == BlockStateValues.JAVA_AIR_ID;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected float getDrag() {
|
||||
return 0.92f;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,53 @@
|
|||
/*
|
||||
* Copyright (c) 2019-2021 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.type.BooleanEntityMetadata;
|
||||
import com.nukkitx.math.vector.Vector3f;
|
||||
import com.nukkitx.protocol.bedrock.data.entity.EntityData;
|
||||
import org.geysermc.connector.network.session.GeyserSession;
|
||||
import org.geysermc.connector.network.translators.world.block.BlockStateValues;
|
||||
|
||||
import java.util.UUID;
|
||||
|
||||
public class FurnaceMinecartEntity extends DefaultBlockMinecartEntity {
|
||||
private boolean hasFuel = false;
|
||||
|
||||
public FurnaceMinecartEntity(GeyserSession session, long entityId, long geyserId, UUID uuid, EntityDefinition<?> definition, Vector3f position, Vector3f motion, float yaw, float pitch, float headYaw) {
|
||||
super(session, entityId, geyserId, uuid, definition, position, motion, yaw, pitch, headYaw);
|
||||
}
|
||||
|
||||
public void setHasFuel(BooleanEntityMetadata entityMetadata) {
|
||||
hasFuel = entityMetadata.getPrimitiveValue();
|
||||
updateDefaultBlockMetadata();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateDefaultBlockMetadata() {
|
||||
dirtyMetadata.put(EntityData.DISPLAY_ITEM, session.getBlockMappings().getBedrockBlockId(hasFuel ? BlockStateValues.JAVA_FURNACE_LIT_ID : BlockStateValues.JAVA_FURNACE_ID));
|
||||
dirtyMetadata.put(EntityData.DISPLAY_OFFSET, 6);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,55 @@
|
|||
/*
|
||||
* Copyright (c) 2019-2021 GeyserMC. http://geysermc.org
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*
|
||||
* @author GeyserMC
|
||||
* @link https://github.com/GeyserMC/Geyser
|
||||
*/
|
||||
|
||||
package org.geysermc.connector.entity;
|
||||
|
||||
import com.nukkitx.protocol.bedrock.data.entity.EntityData;
|
||||
import com.nukkitx.protocol.bedrock.data.entity.EntityDataMap;
|
||||
import it.unimi.dsi.fastutil.objects.Object2ObjectLinkedOpenHashMap;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* A write-only wrapper for temporarily storing entity metadata that will be sent to Bedrock.
|
||||
*/
|
||||
public class GeyserDirtyMetadata {
|
||||
private final Map<EntityData, Object> metadata = new Object2ObjectLinkedOpenHashMap<>();
|
||||
|
||||
public void put(EntityData entityData, Object value) {
|
||||
metadata.put(entityData, value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Applies the contents of the dirty metadata into the input and clears the contents of our map.
|
||||
*/
|
||||
public void apply(EntityDataMap map) {
|
||||
map.putAll(metadata);
|
||||
metadata.clear();
|
||||
}
|
||||
|
||||
public boolean hasEntries() {
|
||||
return !metadata.isEmpty();
|
||||
}
|
||||
}
|
||||
148
core/src/main/java/org/geysermc/connector/entity/ItemEntity.java
Normal file
148
core/src/main/java/org/geysermc/connector/entity/ItemEntity.java
Normal file
|
|
@ -0,0 +1,148 @@
|
|||
/*
|
||||
* Copyright (c) 2019-2021 GeyserMC. http://geysermc.org
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*
|
||||
* @author GeyserMC
|
||||
* @link https://github.com/GeyserMC/Geyser
|
||||
*/
|
||||
|
||||
package org.geysermc.connector.entity;
|
||||
|
||||
import com.github.steveice10.mc.protocol.data.game.entity.metadata.EntityMetadata;
|
||||
import com.github.steveice10.mc.protocol.data.game.entity.metadata.ItemStack;
|
||||
import com.nukkitx.math.vector.Vector3f;
|
||||
import com.nukkitx.math.vector.Vector3i;
|
||||
import com.nukkitx.protocol.bedrock.data.entity.EntityEventType;
|
||||
import com.nukkitx.protocol.bedrock.data.entity.EntityFlag;
|
||||
import com.nukkitx.protocol.bedrock.data.inventory.ItemData;
|
||||
import com.nukkitx.protocol.bedrock.packet.AddItemEntityPacket;
|
||||
import com.nukkitx.protocol.bedrock.packet.EntityEventPacket;
|
||||
import org.geysermc.connector.network.session.GeyserSession;
|
||||
import org.geysermc.connector.network.translators.item.ItemTranslator;
|
||||
import org.geysermc.connector.network.translators.world.block.BlockStateValues;
|
||||
|
||||
import java.util.UUID;
|
||||
|
||||
public class ItemEntity extends ThrowableEntity {
|
||||
protected ItemData item;
|
||||
|
||||
private int waterLevel = -1;
|
||||
|
||||
public ItemEntity(GeyserSession session, long entityId, long geyserId, UUID uuid, EntityDefinition<?> definition, Vector3f position, Vector3f motion, float yaw, float pitch, float headYaw) {
|
||||
super(session, entityId, geyserId, uuid, definition, position, motion, yaw, pitch, headYaw);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void spawnEntity() {
|
||||
if (item == null) {
|
||||
return;
|
||||
}
|
||||
valid = true;
|
||||
AddItemEntityPacket itemPacket = new AddItemEntityPacket();
|
||||
itemPacket.setRuntimeEntityId(geyserId);
|
||||
itemPacket.setUniqueEntityId(geyserId);
|
||||
itemPacket.setPosition(position.add(0d, this.definition.offset(), 0d));
|
||||
itemPacket.setMotion(motion);
|
||||
itemPacket.setFromFishing(false);
|
||||
itemPacket.setItemInHand(item);
|
||||
itemPacket.getMetadata().putFlags(this.flags);
|
||||
dirtyMetadata.apply(itemPacket.getMetadata());
|
||||
|
||||
setFlagsDirty(false);
|
||||
|
||||
session.sendUpstreamPacket(itemPacket);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void tick() {
|
||||
if (isInWater()) {
|
||||
return;
|
||||
}
|
||||
if (!onGround || (motion.getX() * motion.getX() + motion.getZ() * motion.getZ()) > 0.00001) {
|
||||
float gravity = getGravity();
|
||||
motion = motion.down(gravity);
|
||||
moveAbsoluteImmediate(position.add(motion), yaw, pitch, headYaw, onGround, false);
|
||||
float drag = getDrag();
|
||||
motion = motion.mul(drag, 0.98f, drag);
|
||||
}
|
||||
}
|
||||
|
||||
public void setItem(EntityMetadata<ItemStack, ?> entityMetadata) {
|
||||
ItemData item = ItemTranslator.translateToBedrock(session, entityMetadata.getValue());
|
||||
if (this.item == null) {
|
||||
this.item = item;
|
||||
spawnEntity();
|
||||
} else if (item.equals(this.item, false, true, true)) {
|
||||
// Don't bother respawning the entity if items are equal
|
||||
if (this.item.getCount() != item.getCount()) {
|
||||
// Just item count updated; let's make this easy
|
||||
this.item = item;
|
||||
EntityEventPacket packet = new EntityEventPacket();
|
||||
packet.setRuntimeEntityId(geyserId);
|
||||
packet.setType(EntityEventType.UPDATE_ITEM_STACK_SIZE);
|
||||
packet.setData(this.item.getCount());
|
||||
session.sendUpstreamPacket(packet);
|
||||
}
|
||||
} else {
|
||||
this.item = item;
|
||||
despawnEntity();
|
||||
spawnEntity();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void moveAbsoluteImmediate(Vector3f position, float yaw, float pitch, float headYaw, boolean isOnGround, boolean teleported) {
|
||||
float offset = definition.offset();
|
||||
if (waterLevel == 0) { // Item is in a full block of water
|
||||
// Move the item entity down so it doesn't float above the water
|
||||
offset = -definition.offset();
|
||||
}
|
||||
super.moveAbsoluteImmediate(position.add(0, offset, 0), 0, 0, 0, isOnGround, teleported);
|
||||
this.position = position;
|
||||
|
||||
int block = session.getConnector().getWorldManager().getBlockAt(session, position.toInt());
|
||||
waterLevel = BlockStateValues.getWaterLevel(block);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected float getGravity() {
|
||||
if (getFlag(EntityFlag.HAS_GRAVITY) && !onGround && !isInWater()) {
|
||||
// Gravity can change if the item is in water/lava, but
|
||||
// the server calculates the motion & position for us
|
||||
return 0.04f;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected float getDrag() {
|
||||
if (onGround) {
|
||||
Vector3i groundBlockPos = position.toInt().down(1);
|
||||
int blockState = session.getConnector().getWorldManager().getBlockAt(session, groundBlockPos);
|
||||
return BlockStateValues.getSlipperiness(blockState) * 0.98f;
|
||||
}
|
||||
return 0.98f;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean isInWater() {
|
||||
return waterLevel != -1;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,219 @@
|
|||
/*
|
||||
* Copyright (c) 2019-2021 GeyserMC. http://geysermc.org
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*
|
||||
* @author GeyserMC
|
||||
* @link https://github.com/GeyserMC/Geyser
|
||||
*/
|
||||
|
||||
package org.geysermc.connector.entity;
|
||||
|
||||
import com.github.steveice10.mc.protocol.data.game.entity.metadata.EntityMetadata;
|
||||
import com.github.steveice10.mc.protocol.data.game.entity.metadata.ItemStack;
|
||||
import com.github.steveice10.mc.protocol.data.game.entity.metadata.type.IntEntityMetadata;
|
||||
import com.github.steveice10.mc.protocol.data.game.entity.object.Direction;
|
||||
import com.github.steveice10.mc.protocol.data.game.entity.type.EntityType;
|
||||
import com.nukkitx.math.vector.Vector3f;
|
||||
import com.nukkitx.math.vector.Vector3i;
|
||||
import com.nukkitx.nbt.NbtMap;
|
||||
import com.nukkitx.nbt.NbtMapBuilder;
|
||||
import com.nukkitx.protocol.bedrock.data.inventory.ItemData;
|
||||
import com.nukkitx.protocol.bedrock.packet.BlockEntityDataPacket;
|
||||
import com.nukkitx.protocol.bedrock.packet.UpdateBlockPacket;
|
||||
import com.nukkitx.protocol.bedrock.v465.Bedrock_v465;
|
||||
import lombok.Getter;
|
||||
import org.geysermc.connector.network.session.GeyserSession;
|
||||
import org.geysermc.connector.network.translators.item.ItemTranslator;
|
||||
import org.geysermc.connector.registry.type.ItemMapping;
|
||||
|
||||
import java.util.UUID;
|
||||
|
||||
/**
|
||||
* Item frames are an entity in Java but a block entity in Bedrock.
|
||||
*/
|
||||
public class ItemFrameEntity extends Entity {
|
||||
/**
|
||||
* Used for getting the Bedrock block position.
|
||||
* Blocks deal with integers whereas entities deal with floats.
|
||||
*/
|
||||
private final Vector3i bedrockPosition;
|
||||
/**
|
||||
* Specific block 'state' we are emulating in Bedrock.
|
||||
*/
|
||||
private final int bedrockRuntimeId;
|
||||
/**
|
||||
* Rotation of item in frame.
|
||||
*/
|
||||
private float rotation = 0.0f;
|
||||
/**
|
||||
* Cached item frame's Bedrock compound tag.
|
||||
*/
|
||||
private NbtMap cachedTag;
|
||||
/**
|
||||
* The item currently in the item frame. Used for block picking.
|
||||
*/
|
||||
@Getter
|
||||
private ItemStack heldItem = null;
|
||||
/**
|
||||
* Determines if this entity needs updated on the client end/
|
||||
*/
|
||||
private boolean changed = true;
|
||||
|
||||
public ItemFrameEntity(GeyserSession session, long entityId, long geyserId, UUID uuid, EntityDefinition<?> definition, Vector3f position, Vector3f motion, float yaw, float pitch, Direction direction) {
|
||||
super(session, entityId, geyserId, uuid, definition, position, motion, yaw, pitch, 0f);
|
||||
|
||||
NbtMapBuilder blockBuilder = NbtMap.builder()
|
||||
.putString("name", this.definition.entityType() == EntityType.GLOW_ITEM_FRAME ? "minecraft:glow_frame" : "minecraft:frame")
|
||||
.putInt("version", session.getBlockMappings().getBlockStateVersion());
|
||||
NbtMapBuilder statesBuilder = NbtMap.builder()
|
||||
.putInt("facing_direction", direction.ordinal())
|
||||
.putByte("item_frame_map_bit", (byte) 0);
|
||||
if (session.getUpstream().getProtocolVersion() >= Bedrock_v465.V465_CODEC.getProtocolVersion()) {
|
||||
statesBuilder.putByte("item_frame_photo_bit", (byte) 0);
|
||||
}
|
||||
blockBuilder.put("states", statesBuilder.build());
|
||||
|
||||
bedrockRuntimeId = session.getBlockMappings().getItemFrame(blockBuilder.build());
|
||||
bedrockPosition = Vector3i.from(position.getFloorX(), position.getFloorY(), position.getFloorZ());
|
||||
|
||||
session.getItemFrameCache().put(bedrockPosition, this);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void initializeMetadata() {
|
||||
// lol nah don't do anything
|
||||
// This isn't a real entity for Bedrock so it isn't going to do anything
|
||||
}
|
||||
|
||||
@Override
|
||||
public void spawnEntity() {
|
||||
updateBlock(true);
|
||||
session.getConnector().getLogger().debug("Spawned item frame at location " + bedrockPosition + " with java id " + entityId);
|
||||
valid = true;
|
||||
}
|
||||
|
||||
public void setItemInFrame(EntityMetadata<ItemStack, ?> entityMetadata) {
|
||||
if (entityMetadata.getValue() != null) {
|
||||
this.heldItem = entityMetadata.getValue();
|
||||
ItemData itemData = ItemTranslator.translateToBedrock(session, heldItem);
|
||||
ItemMapping mapping = session.getItemMappings().getMapping(entityMetadata.getValue());
|
||||
NbtMapBuilder builder = NbtMap.builder();
|
||||
|
||||
builder.putByte("Count", (byte) itemData.getCount());
|
||||
if (itemData.getTag() != null) {
|
||||
builder.put("tag", itemData.getTag());
|
||||
}
|
||||
builder.putShort("Damage", (short) itemData.getDamage());
|
||||
builder.putString("Name", mapping.getBedrockIdentifier());
|
||||
NbtMapBuilder tag = getDefaultTag().toBuilder();
|
||||
tag.put("Item", builder.build());
|
||||
tag.putFloat("ItemDropChance", 1.0f);
|
||||
tag.putFloat("ItemRotation", rotation);
|
||||
cachedTag = tag.build();
|
||||
changed = true;
|
||||
} else if (cachedTag != null) {
|
||||
cachedTag = getDefaultTag();
|
||||
changed = true;
|
||||
}
|
||||
}
|
||||
|
||||
public void setItemRotation(IntEntityMetadata entityMetadata) {
|
||||
rotation = entityMetadata.getPrimitiveValue() * 45;
|
||||
if (cachedTag == null) {
|
||||
return;
|
||||
}
|
||||
NbtMapBuilder builder = cachedTag.toBuilder();
|
||||
builder.putFloat("ItemRotation", rotation);
|
||||
cachedTag = builder.build();
|
||||
changed = true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean despawnEntity() {
|
||||
UpdateBlockPacket updateBlockPacket = new UpdateBlockPacket();
|
||||
updateBlockPacket.setDataLayer(0);
|
||||
updateBlockPacket.setBlockPosition(bedrockPosition);
|
||||
updateBlockPacket.setRuntimeId(session.getBlockMappings().getBedrockAirId()); //TODO maybe set this to the world block or another item frame?
|
||||
updateBlockPacket.getFlags().add(UpdateBlockPacket.Flag.PRIORITY);
|
||||
updateBlockPacket.getFlags().add(UpdateBlockPacket.Flag.NETWORK);
|
||||
updateBlockPacket.getFlags().add(UpdateBlockPacket.Flag.NEIGHBORS);
|
||||
session.sendUpstreamPacket(updateBlockPacket);
|
||||
|
||||
session.getItemFrameCache().remove(bedrockPosition, this);
|
||||
|
||||
valid = false;
|
||||
return true;
|
||||
}
|
||||
|
||||
private NbtMap getDefaultTag() {
|
||||
NbtMapBuilder builder = NbtMap.builder();
|
||||
builder.putInt("x", bedrockPosition.getX());
|
||||
builder.putInt("y", bedrockPosition.getY());
|
||||
builder.putInt("z", bedrockPosition.getZ());
|
||||
builder.putByte("isMovable", (byte) 1);
|
||||
builder.putString("id", this.definition.entityType() == EntityType.GLOW_ITEM_FRAME ? "GlowItemFrame" : "ItemFrame");
|
||||
return builder.build();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateBedrockMetadata() {
|
||||
updateBlock(false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates the item frame as a block
|
||||
*/
|
||||
public void updateBlock(boolean force) {
|
||||
if (!changed && !force) {
|
||||
// Don't send a block update packet - nothing changed
|
||||
return;
|
||||
}
|
||||
UpdateBlockPacket updateBlockPacket = new UpdateBlockPacket();
|
||||
updateBlockPacket.setDataLayer(0);
|
||||
updateBlockPacket.setBlockPosition(bedrockPosition);
|
||||
updateBlockPacket.setRuntimeId(bedrockRuntimeId);
|
||||
updateBlockPacket.getFlags().add(UpdateBlockPacket.Flag.PRIORITY);
|
||||
updateBlockPacket.getFlags().add(UpdateBlockPacket.Flag.NETWORK);
|
||||
updateBlockPacket.getFlags().add(UpdateBlockPacket.Flag.NEIGHBORS);
|
||||
session.sendUpstreamPacket(updateBlockPacket);
|
||||
|
||||
BlockEntityDataPacket blockEntityDataPacket = new BlockEntityDataPacket();
|
||||
blockEntityDataPacket.setBlockPosition(bedrockPosition);
|
||||
if (cachedTag != null) {
|
||||
blockEntityDataPacket.setData(cachedTag);
|
||||
} else {
|
||||
blockEntityDataPacket.setData(getDefaultTag());
|
||||
}
|
||||
|
||||
session.sendUpstreamPacket(blockEntityDataPacket);
|
||||
|
||||
changed = false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Finds the Java entity ID of an item frame from its Bedrock position.
|
||||
* @param position position of item frame in Bedrock.
|
||||
* @param session GeyserSession.
|
||||
* @return Java entity ID or -1 if not found.
|
||||
*/
|
||||
public static ItemFrameEntity getItemFrameEntity(GeyserSession session, Vector3i position) {
|
||||
return session.getItemFrameCache().get(position);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,76 @@
|
|||
/*
|
||||
* Copyright (c) 2019-2021 GeyserMC. http://geysermc.org
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*
|
||||
* @author GeyserMC
|
||||
* @link https://github.com/GeyserMC/Geyser
|
||||
*/
|
||||
|
||||
package org.geysermc.connector.entity;
|
||||
|
||||
import com.nukkitx.math.vector.Vector3f;
|
||||
import org.geysermc.connector.network.session.GeyserSession;
|
||||
|
||||
import java.util.UUID;
|
||||
|
||||
public class ItemedFireballEntity extends ThrowableEntity {
|
||||
private final Vector3f acceleration;
|
||||
|
||||
/**
|
||||
* The number of ticks to advance movement before sending to Bedrock
|
||||
*/
|
||||
protected int futureTicks = 3;
|
||||
|
||||
public ItemedFireballEntity(GeyserSession session, long entityId, long geyserId, UUID uuid, EntityDefinition<?> definition, Vector3f position, Vector3f motion, float yaw, float pitch, float headYaw) {
|
||||
super(session, entityId, geyserId, uuid, definition, position, Vector3f.ZERO, yaw, pitch, headYaw);
|
||||
|
||||
float magnitude = motion.length();
|
||||
if (magnitude != 0) {
|
||||
acceleration = motion.div(magnitude).mul(0.1f);
|
||||
} else {
|
||||
acceleration = Vector3f.ZERO;
|
||||
}
|
||||
}
|
||||
|
||||
private Vector3f tickMovement(Vector3f position) {
|
||||
position = position.add(motion);
|
||||
float drag = getDrag();
|
||||
motion = motion.add(acceleration).mul(drag);
|
||||
return position;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void moveAbsoluteImmediate(Vector3f position, float yaw, float pitch, float headYaw, boolean isOnGround, boolean teleported) {
|
||||
// Advance the position by a few ticks before sending it to Bedrock
|
||||
Vector3f lastMotion = motion;
|
||||
Vector3f newPosition = position;
|
||||
for (int i = 0; i < futureTicks; i++) {
|
||||
newPosition = tickMovement(newPosition);
|
||||
}
|
||||
super.moveAbsoluteImmediate(newPosition, yaw, pitch, headYaw, isOnGround, teleported);
|
||||
this.position = position;
|
||||
this.motion = lastMotion;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void tick() {
|
||||
moveAbsoluteImmediate(tickMovement(position), yaw, pitch, headYaw, false, false);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,40 @@
|
|||
/*
|
||||
* Copyright (c) 2019-2021 GeyserMC. http://geysermc.org
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*
|
||||
* @author GeyserMC
|
||||
* @link https://github.com/GeyserMC/Geyser
|
||||
*/
|
||||
|
||||
package org.geysermc.connector.entity;
|
||||
|
||||
import com.nukkitx.math.vector.Vector3f;
|
||||
import org.geysermc.connector.network.session.GeyserSession;
|
||||
|
||||
import java.util.UUID;
|
||||
|
||||
public class LeashKnotEntity extends Entity {
|
||||
|
||||
public LeashKnotEntity(GeyserSession session, long entityId, long geyserId, UUID uuid, EntityDefinition<?> definition, Vector3f position, Vector3f motion, float yaw, float pitch, float headYaw) {
|
||||
// Position is incorrect by default
|
||||
super(session, entityId, geyserId, uuid, definition, position.add(0.5f, 0.25f, 0.5f), motion, yaw, pitch, headYaw);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,62 @@
|
|||
/*
|
||||
* Copyright (c) 2019-2021 GeyserMC. http://geysermc.org
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*
|
||||
* @author GeyserMC
|
||||
* @link https://github.com/GeyserMC/Geyser
|
||||
*/
|
||||
|
||||
package org.geysermc.connector.entity;
|
||||
|
||||
import com.nukkitx.math.vector.Vector3f;
|
||||
import com.nukkitx.protocol.bedrock.packet.PlaySoundPacket;
|
||||
import org.geysermc.connector.network.session.GeyserSession;
|
||||
|
||||
import java.util.UUID;
|
||||
import java.util.concurrent.ThreadLocalRandom;
|
||||
|
||||
public class LightningEntity extends Entity {
|
||||
|
||||
public LightningEntity(GeyserSession session, long entityId, long geyserId, UUID uuid, EntityDefinition<?> definition, Vector3f position, Vector3f motion, float yaw, float pitch, float headYaw) {
|
||||
super(session, entityId, geyserId, uuid, definition, position, motion, yaw, pitch, headYaw);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void spawnEntity() {
|
||||
super.spawnEntity();
|
||||
|
||||
// Add these two sound effects - they're done completely clientside on Java Edition as of 1.17.1
|
||||
ThreadLocalRandom random = ThreadLocalRandom.current();
|
||||
|
||||
PlaySoundPacket thunderPacket = new PlaySoundPacket();
|
||||
thunderPacket.setPosition(this.position);
|
||||
thunderPacket.setSound("ambient.weather.thunder");
|
||||
thunderPacket.setPitch(0.8f + random.nextFloat() * 0.2f);
|
||||
thunderPacket.setVolume(10000f); // Really.
|
||||
session.sendUpstreamPacket(thunderPacket);
|
||||
|
||||
PlaySoundPacket impactPacket = new PlaySoundPacket();
|
||||
impactPacket.setPosition(this.position);
|
||||
impactPacket.setSound("ambient.weather.lightning.impact");
|
||||
impactPacket.setPitch(0.5f + random.nextFloat() * 0.2f);
|
||||
impactPacket.setVolume(2.0f);
|
||||
session.sendUpstreamPacket(impactPacket);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,273 @@
|
|||
/*
|
||||
* Copyright (c) 2019-2021 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.attribute.Attribute;
|
||||
import com.github.steveice10.mc.protocol.data.game.entity.metadata.EntityMetadata;
|
||||
import com.github.steveice10.mc.protocol.data.game.entity.metadata.Pose;
|
||||
import com.github.steveice10.mc.protocol.data.game.entity.metadata.Position;
|
||||
import com.github.steveice10.mc.protocol.data.game.entity.metadata.type.ByteEntityMetadata;
|
||||
import com.github.steveice10.mc.protocol.data.game.entity.metadata.type.FloatEntityMetadata;
|
||||
import com.github.steveice10.mc.protocol.data.game.entity.metadata.type.IntEntityMetadata;
|
||||
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;
|
||||
import com.nukkitx.protocol.bedrock.data.inventory.ContainerId;
|
||||
import com.nukkitx.protocol.bedrock.data.inventory.ItemData;
|
||||
import com.nukkitx.protocol.bedrock.packet.MobArmorEquipmentPacket;
|
||||
import com.nukkitx.protocol.bedrock.packet.MobEquipmentPacket;
|
||||
import com.nukkitx.protocol.bedrock.packet.UpdateAttributesPacket;
|
||||
import lombok.AccessLevel;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
import org.geysermc.connector.entity.attribute.GeyserAttributeType;
|
||||
import org.geysermc.connector.network.session.GeyserSession;
|
||||
import org.geysermc.connector.registry.type.ItemMapping;
|
||||
import org.geysermc.connector.utils.AttributeUtils;
|
||||
import org.geysermc.connector.utils.ChunkUtils;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
import java.util.UUID;
|
||||
|
||||
@Getter
|
||||
@Setter
|
||||
public class LivingEntity extends Entity {
|
||||
|
||||
protected ItemData helmet = ItemData.AIR;
|
||||
protected ItemData chestplate = ItemData.AIR;
|
||||
protected ItemData leggings = ItemData.AIR;
|
||||
protected ItemData boots = ItemData.AIR;
|
||||
protected ItemData hand = ItemData.AIR;
|
||||
protected ItemData offHand = ItemData.AIR;
|
||||
|
||||
@Getter(value = AccessLevel.NONE)
|
||||
protected float health = 1f; // The default value in Java Edition before any entity metadata is sent
|
||||
@Getter(value = AccessLevel.NONE)
|
||||
protected float maxHealth = 20f; // The value Java Edition defaults to if no attribute is given
|
||||
|
||||
/**
|
||||
* A convenience variable for if the entity has reached the maximum frozen ticks and should be shaking
|
||||
*/
|
||||
private boolean isMaxFrozenState = false;
|
||||
|
||||
public LivingEntity(GeyserSession session, long entityId, long geyserId, UUID uuid, EntityDefinition<?> definition, Vector3f position, Vector3f motion, float yaw, float pitch, float headYaw) {
|
||||
super(session, entityId, geyserId, uuid, definition, position, motion, yaw, pitch, headYaw);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void initializeMetadata() {
|
||||
super.initializeMetadata();
|
||||
// Matches Bedrock behavior; is always set to this
|
||||
dirtyMetadata.put(EntityData.HEALTH, 1);
|
||||
}
|
||||
|
||||
public void setLivingEntityFlags(ByteEntityMetadata entityMetadata) {
|
||||
byte xd = entityMetadata.getPrimitiveValue();
|
||||
|
||||
// Blocking gets triggered when using a bow, but if we set USING_ITEM for all items, it may look like
|
||||
// you're "mining" with ex. a shield.
|
||||
ItemMapping shield = session.getItemMappings().getStoredItems().shield();
|
||||
boolean isUsingShield = (getHand().getId() == shield.getBedrockId() ||
|
||||
getHand().equals(ItemData.AIR) && getOffHand().getId() == shield.getBedrockId());
|
||||
setFlag(EntityFlag.USING_ITEM, (xd & 0x01) == 0x01 && !isUsingShield);
|
||||
setFlag(EntityFlag.BLOCKING, (xd & 0x01) == 0x01);
|
||||
|
||||
// Riptide spin attack
|
||||
setFlag(EntityFlag.DAMAGE_NEARBY_MOBS, (xd & 0x04) == 0x04);
|
||||
}
|
||||
|
||||
public void setHealth(FloatEntityMetadata entityMetadata) {
|
||||
this.health = entityMetadata.getPrimitiveValue();
|
||||
|
||||
AttributeData healthData = createHealthAttribute();
|
||||
UpdateAttributesPacket attributesPacket = new UpdateAttributesPacket();
|
||||
attributesPacket.setRuntimeEntityId(geyserId);
|
||||
attributesPacket.setAttributes(Collections.singletonList(healthData));
|
||||
session.sendUpstreamPacket(attributesPacket);
|
||||
}
|
||||
|
||||
public Vector3i setBedPosition(EntityMetadata<Optional<Position>, ?> entityMetadata) {
|
||||
Optional<Position> optionalPos = entityMetadata.getValue();
|
||||
if (optionalPos.isPresent()) {
|
||||
Position bedPosition = optionalPos.get();
|
||||
Vector3i vector = Vector3i.from(bedPosition.getX(), bedPosition.getY(), bedPosition.getZ());
|
||||
dirtyMetadata.put(EntityData.BED_POSITION, vector);
|
||||
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);
|
||||
// Indicate that the player should enter the sleep cycle
|
||||
// Has to be a byte or it does not work
|
||||
// (Bed position is what actually triggers sleep - "pose" is only optional)
|
||||
dirtyMetadata.put(EntityData.PLAYER_FLAGS, (byte) 2);
|
||||
return vector;
|
||||
} else {
|
||||
// Player is no longer sleeping
|
||||
dirtyMetadata.put(EntityData.PLAYER_FLAGS, (byte) 0);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean isShaking() {
|
||||
return isMaxFrozenState;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void setDimensions(Pose pose) {
|
||||
if (pose == Pose.SLEEPING) {
|
||||
setBoundingBoxWidth(0.2f);
|
||||
setBoundingBoxHeight(0.2f);
|
||||
} else {
|
||||
super.setDimensions(pose);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public float setFreezing(IntEntityMetadata entityMetadata) {
|
||||
float freezingPercentage = super.setFreezing(entityMetadata);
|
||||
this.isMaxFrozenState = freezingPercentage >= 1.0f;
|
||||
setFlag(EntityFlag.SHAKING, isShaking());
|
||||
return freezingPercentage;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return a Bedrock health attribute constructed from the data sent from the server
|
||||
*/
|
||||
protected AttributeData createHealthAttribute() {
|
||||
// Default health needs to be specified as the max health in order for maximum hearts to show correctly on mounted entities
|
||||
// Round health value up, so that Bedrock doesn't consider the entity to be dead when health is between 0 and 1
|
||||
return new AttributeData(GeyserAttributeType.HEALTH.getBedrockIdentifier(), 0f, this.maxHealth, (float) Math.ceil(this.health), this.maxHealth);
|
||||
}
|
||||
|
||||
public void updateArmor(GeyserSession session) {
|
||||
if (!valid) return;
|
||||
|
||||
ItemData helmet = this.helmet;
|
||||
ItemData chestplate = this.chestplate;
|
||||
// If an entity has a banner on them, it will be in the helmet slot in Java but the chestplate spot in Bedrock
|
||||
// But don't overwrite the chestplate if it isn't empty
|
||||
ItemMapping banner = session.getItemMappings().getStoredItems().banner();
|
||||
if (chestplate.getId() == ItemData.AIR.getId() && helmet.getId() == banner.getBedrockId()) {
|
||||
chestplate = this.helmet;
|
||||
helmet = ItemData.AIR;
|
||||
} else if (chestplate.getId() == banner.getBedrockId()) {
|
||||
// Prevent chestplate banners from showing erroneously
|
||||
chestplate = ItemData.AIR;
|
||||
}
|
||||
|
||||
MobArmorEquipmentPacket armorEquipmentPacket = new MobArmorEquipmentPacket();
|
||||
armorEquipmentPacket.setRuntimeEntityId(geyserId);
|
||||
armorEquipmentPacket.setHelmet(helmet);
|
||||
armorEquipmentPacket.setChestplate(chestplate);
|
||||
armorEquipmentPacket.setLeggings(leggings);
|
||||
armorEquipmentPacket.setBoots(boots);
|
||||
|
||||
session.sendUpstreamPacket(armorEquipmentPacket);
|
||||
}
|
||||
|
||||
public void updateMainHand(GeyserSession session) {
|
||||
if (!valid) return;
|
||||
|
||||
MobEquipmentPacket handPacket = new MobEquipmentPacket();
|
||||
handPacket.setRuntimeEntityId(geyserId);
|
||||
handPacket.setItem(hand);
|
||||
handPacket.setHotbarSlot(-1);
|
||||
handPacket.setInventorySlot(0);
|
||||
handPacket.setContainerId(ContainerId.INVENTORY);
|
||||
|
||||
session.sendUpstreamPacket(handPacket);
|
||||
}
|
||||
|
||||
public void updateOffHand(GeyserSession session) {
|
||||
if (!valid) return;
|
||||
|
||||
MobEquipmentPacket offHandPacket = new MobEquipmentPacket();
|
||||
offHandPacket.setRuntimeEntityId(geyserId);
|
||||
offHandPacket.setItem(offHand);
|
||||
offHandPacket.setHotbarSlot(-1);
|
||||
offHandPacket.setInventorySlot(0);
|
||||
offHandPacket.setContainerId(ContainerId.OFFHAND);
|
||||
|
||||
session.sendUpstreamPacket(offHandPacket);
|
||||
}
|
||||
|
||||
/**
|
||||
* Attributes are properties of an entity that are generally more runtime-based instead of permanent properties.
|
||||
* Movement speed, current attack damage with a weapon, current knockback resistance.
|
||||
*
|
||||
* @param attributes the Java list of attributes sent from the server
|
||||
*/
|
||||
public void updateBedrockAttributes(GeyserSession session, List<Attribute> attributes) {
|
||||
if (!valid) return;
|
||||
|
||||
List<AttributeData> newAttributes = new ArrayList<>();
|
||||
|
||||
for (Attribute attribute : attributes) {
|
||||
// Convert the attribute to a Bedrock version, if relevant
|
||||
updateAttribute(attribute, newAttributes);
|
||||
}
|
||||
|
||||
if (newAttributes.isEmpty()) {
|
||||
// If there are Java-only attributes or only attributes that are not translated by us
|
||||
return;
|
||||
}
|
||||
|
||||
UpdateAttributesPacket updateAttributesPacket = new UpdateAttributesPacket();
|
||||
updateAttributesPacket.setRuntimeEntityId(geyserId);
|
||||
updateAttributesPacket.setAttributes(newAttributes);
|
||||
session.sendUpstreamPacket(updateAttributesPacket);
|
||||
}
|
||||
|
||||
/**
|
||||
* Takes the Java attribute and adds it to newAttributes as a Bedrock-formatted attribute
|
||||
*/
|
||||
protected void updateAttribute(Attribute javaAttribute, List<AttributeData> newAttributes) {
|
||||
switch (javaAttribute.getType()) {
|
||||
case GENERIC_MAX_HEALTH -> {
|
||||
this.maxHealth = (float) AttributeUtils.calculateValue(javaAttribute);
|
||||
newAttributes.add(createHealthAttribute());
|
||||
}
|
||||
case GENERIC_ATTACK_DAMAGE -> newAttributes.add(calculateAttribute(javaAttribute, GeyserAttributeType.ATTACK_DAMAGE));
|
||||
case GENERIC_FLYING_SPEED -> newAttributes.add(calculateAttribute(javaAttribute, GeyserAttributeType.FLYING_SPEED));
|
||||
case GENERIC_MOVEMENT_SPEED -> newAttributes.add(calculateAttribute(javaAttribute, GeyserAttributeType.MOVEMENT_SPEED));
|
||||
case GENERIC_FOLLOW_RANGE -> newAttributes.add(calculateAttribute(javaAttribute, GeyserAttributeType.FOLLOW_RANGE));
|
||||
case GENERIC_KNOCKBACK_RESISTANCE -> newAttributes.add(calculateAttribute(javaAttribute, GeyserAttributeType.KNOCKBACK_RESISTANCE));
|
||||
case HORSE_JUMP_STRENGTH -> newAttributes.add(calculateAttribute(javaAttribute, GeyserAttributeType.HORSE_JUMP_STRENGTH));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculates the complete attribute value to send to Bedrock. Will be overriden if attributes need to be cached.
|
||||
*/
|
||||
protected AttributeData calculateAttribute(Attribute javaAttribute, GeyserAttributeType type) {
|
||||
return type.getAttribute((float) AttributeUtils.calculateValue(javaAttribute));
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,66 @@
|
|||
/*
|
||||
* Copyright (c) 2019-2021 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.type.BooleanEntityMetadata;
|
||||
import com.github.steveice10.mc.protocol.data.game.entity.metadata.type.IntEntityMetadata;
|
||||
import com.nukkitx.math.vector.Vector3f;
|
||||
import com.nukkitx.protocol.bedrock.data.entity.EntityData;
|
||||
import org.geysermc.connector.network.session.GeyserSession;
|
||||
|
||||
import java.util.UUID;
|
||||
|
||||
public class MinecartEntity extends Entity {
|
||||
|
||||
public MinecartEntity(GeyserSession session, long entityId, long geyserId, UUID uuid, EntityDefinition<?> definition, Vector3f position, Vector3f motion, float yaw, float pitch, float headYaw) {
|
||||
super(session, entityId, geyserId, uuid, definition, position.add(0d, definition.offset(), 0d), motion, yaw, pitch, headYaw);
|
||||
}
|
||||
|
||||
public void setCustomBlock(IntEntityMetadata entityMetadata) {
|
||||
dirtyMetadata.put(EntityData.DISPLAY_ITEM, session.getBlockMappings().getBedrockBlockId(entityMetadata.getPrimitiveValue()));
|
||||
}
|
||||
|
||||
public void setCustomBlockOffset(IntEntityMetadata entityMetadata) {
|
||||
dirtyMetadata.put(EntityData.DISPLAY_OFFSET, entityMetadata.getPrimitiveValue());
|
||||
}
|
||||
|
||||
public void setShowCustomBlock(BooleanEntityMetadata entityMetadata) {
|
||||
// If the custom block should be enabled
|
||||
// Needs a byte based off of Java's boolean
|
||||
dirtyMetadata.put(EntityData.CUSTOM_DISPLAY, (byte) (entityMetadata.getPrimitiveValue() ? 1 : 0));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void moveAbsolute(Vector3f position, float yaw, float pitch, float headYaw, boolean isOnGround, boolean teleported) {
|
||||
super.moveAbsolute(position.add(0d, this.definition.offset(), 0d), yaw, pitch, headYaw, isOnGround, teleported);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Vector3f getBedrockRotation() {
|
||||
// Note: minecart rotation on rails does not care about the actual rotation value
|
||||
return Vector3f.from(0, yaw, 0);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,80 @@
|
|||
/*
|
||||
* Copyright (c) 2019-2021 GeyserMC. http://geysermc.org
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*
|
||||
* @author GeyserMC
|
||||
* @link https://github.com/GeyserMC/Geyser
|
||||
*/
|
||||
|
||||
package org.geysermc.connector.entity;
|
||||
|
||||
import com.nukkitx.math.vector.Vector3f;
|
||||
import com.nukkitx.protocol.bedrock.packet.AddPaintingPacket;
|
||||
import org.geysermc.connector.network.session.GeyserSession;
|
||||
import org.geysermc.connector.utils.PaintingType;
|
||||
|
||||
import java.util.UUID;
|
||||
|
||||
public class PaintingEntity extends Entity {
|
||||
private static final double OFFSET = -0.46875;
|
||||
private final PaintingType paintingName;
|
||||
private final int direction;
|
||||
|
||||
public PaintingEntity(GeyserSession session, long entityId, long geyserId, UUID uuid, Vector3f position, PaintingType paintingName, int direction) {
|
||||
super(session, entityId, geyserId, uuid, EntityDefinitions.PAINTING, position, Vector3f.ZERO, 0f, 0f, 0f);
|
||||
this.paintingName = paintingName;
|
||||
this.direction = direction;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void spawnEntity() {
|
||||
AddPaintingPacket addPaintingPacket = new AddPaintingPacket();
|
||||
addPaintingPacket.setUniqueEntityId(geyserId);
|
||||
addPaintingPacket.setRuntimeEntityId(geyserId);
|
||||
addPaintingPacket.setMotive(paintingName.getBedrockName());
|
||||
addPaintingPacket.setPosition(fixOffset());
|
||||
addPaintingPacket.setDirection(direction);
|
||||
session.sendUpstreamPacket(addPaintingPacket);
|
||||
|
||||
valid = true;
|
||||
|
||||
session.getConnector().getLogger().debug("Spawned painting on " + position);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateHeadLookRotation(float headYaw) {
|
||||
// Do nothing, as head look messes up paintings
|
||||
}
|
||||
|
||||
private Vector3f fixOffset() {
|
||||
Vector3f position = super.position;
|
||||
position = position.add(0.5, 0.5, 0.5);
|
||||
double widthOffset = paintingName.getWidth() > 1 ? 0.5 : 0;
|
||||
double heightOffset = paintingName.getHeight() > 1 && paintingName.getHeight() != 3 ? 0.5 : 0;
|
||||
|
||||
return switch (direction) {
|
||||
case 0 -> position.add(widthOffset, heightOffset, OFFSET);
|
||||
case 1 -> position.add(-OFFSET, heightOffset, widthOffset);
|
||||
case 2 -> position.add(-widthOffset, heightOffset, -OFFSET);
|
||||
case 3 -> position.add(OFFSET, heightOffset, -widthOffset);
|
||||
default -> position;
|
||||
};
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,46 @@
|
|||
/*
|
||||
* Copyright (c) 2019-2021 GeyserMC. http://geysermc.org
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*
|
||||
* @author GeyserMC
|
||||
* @link https://github.com/GeyserMC/Geyser
|
||||
*/
|
||||
|
||||
package org.geysermc.connector.entity;
|
||||
|
||||
import com.nukkitx.math.vector.Vector3f;
|
||||
import com.nukkitx.protocol.bedrock.data.entity.EntityData;
|
||||
import org.geysermc.connector.network.session.GeyserSession;
|
||||
import org.geysermc.connector.network.translators.world.block.BlockStateValues;
|
||||
|
||||
import java.util.UUID;
|
||||
|
||||
public class SpawnerMinecartEntity extends DefaultBlockMinecartEntity {
|
||||
|
||||
public SpawnerMinecartEntity(GeyserSession session, long entityId, long geyserId, UUID uuid, EntityDefinition<?> definition, Vector3f position, Vector3f motion, float yaw, float pitch, float headYaw) {
|
||||
super(session, entityId, geyserId, uuid, definition, position, motion, yaw, pitch, headYaw);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateDefaultBlockMetadata() {
|
||||
dirtyMetadata.put(EntityData.DISPLAY_ITEM, session.getBlockMappings().getBedrockBlockId(BlockStateValues.JAVA_SPAWNER_ID));
|
||||
dirtyMetadata.put(EntityData.DISPLAY_OFFSET, 6);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,68 @@
|
|||
/*
|
||||
* Copyright (c) 2019-2021 GeyserMC. http://geysermc.org
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*
|
||||
* @author GeyserMC
|
||||
* @link https://github.com/GeyserMC/Geyser
|
||||
*/
|
||||
|
||||
package org.geysermc.connector.entity;
|
||||
|
||||
import com.github.steveice10.mc.protocol.data.game.entity.metadata.EntityMetadata;
|
||||
import com.github.steveice10.mc.protocol.data.game.entity.metadata.type.IntEntityMetadata;
|
||||
import com.nukkitx.math.vector.Vector3f;
|
||||
import com.nukkitx.protocol.bedrock.data.entity.EntityData;
|
||||
import com.nukkitx.protocol.bedrock.data.entity.EntityFlag;
|
||||
import com.nukkitx.protocol.bedrock.packet.SetEntityDataPacket;
|
||||
import org.geysermc.connector.network.session.GeyserSession;
|
||||
|
||||
import java.util.UUID;
|
||||
|
||||
public class TNTEntity extends Entity implements Tickable {
|
||||
private int currentTick;
|
||||
|
||||
public TNTEntity(GeyserSession session, long entityId, long geyserId, UUID uuid, EntityDefinition<?> definition, Vector3f position, Vector3f motion, float yaw, float pitch, float headYaw) {
|
||||
super(session, entityId, geyserId, uuid, definition, position, motion, yaw, pitch, headYaw);
|
||||
}
|
||||
|
||||
public void setFuseLength(IntEntityMetadata entityMetadata) {
|
||||
currentTick = ((IntEntityMetadata) entityMetadata).getPrimitiveValue();
|
||||
setFlag(EntityFlag.IGNITED, true);
|
||||
dirtyMetadata.put(EntityData.FUSE_LENGTH, currentTick);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void tick() {
|
||||
if (currentTick == 0) {
|
||||
// No need to update the fuse when there is none
|
||||
return;
|
||||
}
|
||||
|
||||
if (currentTick % 5 == 0) {
|
||||
dirtyMetadata.put(EntityData.FUSE_LENGTH, currentTick);
|
||||
|
||||
SetEntityDataPacket packet = new SetEntityDataPacket();
|
||||
packet.setRuntimeEntityId(geyserId);
|
||||
packet.getMetadata().put(EntityData.FUSE_LENGTH, currentTick);
|
||||
session.sendUpstreamPacket(packet);
|
||||
}
|
||||
currentTick--;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,194 @@
|
|||
/*
|
||||
* Copyright (c) 2019-2021 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.type.EntityType;
|
||||
import com.nukkitx.math.vector.Vector3f;
|
||||
import com.nukkitx.protocol.bedrock.data.LevelEventType;
|
||||
import com.nukkitx.protocol.bedrock.data.entity.EntityFlag;
|
||||
import com.nukkitx.protocol.bedrock.packet.LevelEventPacket;
|
||||
import com.nukkitx.protocol.bedrock.packet.MoveEntityDeltaPacket;
|
||||
import org.geysermc.connector.network.session.GeyserSession;
|
||||
import org.geysermc.connector.network.translators.world.block.BlockStateValues;
|
||||
|
||||
import java.util.UUID;
|
||||
|
||||
/**
|
||||
* Used as a class for any object-like entity that moves as a projectile
|
||||
*/
|
||||
public class ThrowableEntity extends Entity implements Tickable {
|
||||
|
||||
protected Vector3f lastJavaPosition;
|
||||
|
||||
public ThrowableEntity(GeyserSession session, long entityId, long geyserId, UUID uuid, EntityDefinition<?> definition, Vector3f position, Vector3f motion, float yaw, float pitch, float headYaw) {
|
||||
super(session, entityId, geyserId, uuid, definition, position, motion, yaw, pitch, headYaw);
|
||||
this.lastJavaPosition = position;
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates the position for the Bedrock client.
|
||||
*
|
||||
* Java clients assume the next positions of moving items. Bedrock needs to be explicitly told positions
|
||||
*/
|
||||
@Override
|
||||
public void tick() {
|
||||
moveAbsoluteImmediate(position.add(motion), yaw, pitch, headYaw, onGround, false);
|
||||
float drag = getDrag();
|
||||
float gravity = getGravity();
|
||||
motion = motion.mul(drag).down(gravity);
|
||||
}
|
||||
|
||||
protected void moveAbsoluteImmediate(Vector3f position, float yaw, float pitch, float headYaw, boolean isOnGround, boolean teleported) {
|
||||
MoveEntityDeltaPacket moveEntityDeltaPacket = new MoveEntityDeltaPacket();
|
||||
moveEntityDeltaPacket.setRuntimeEntityId(geyserId);
|
||||
|
||||
if (isOnGround) {
|
||||
moveEntityDeltaPacket.getFlags().add(MoveEntityDeltaPacket.Flag.ON_GROUND);
|
||||
}
|
||||
setOnGround(isOnGround);
|
||||
|
||||
if (teleported) {
|
||||
moveEntityDeltaPacket.getFlags().add(MoveEntityDeltaPacket.Flag.TELEPORTING);
|
||||
}
|
||||
|
||||
if (this.position.getX() != position.getX()) {
|
||||
moveEntityDeltaPacket.getFlags().add(MoveEntityDeltaPacket.Flag.HAS_X);
|
||||
moveEntityDeltaPacket.setX(position.getX());
|
||||
}
|
||||
if (this.position.getY() != position.getY()) {
|
||||
moveEntityDeltaPacket.getFlags().add(MoveEntityDeltaPacket.Flag.HAS_Y);
|
||||
moveEntityDeltaPacket.setY(position.getY());
|
||||
}
|
||||
if (this.position.getZ() != position.getZ()) {
|
||||
moveEntityDeltaPacket.getFlags().add(MoveEntityDeltaPacket.Flag.HAS_Z);
|
||||
moveEntityDeltaPacket.setZ(position.getZ());
|
||||
}
|
||||
setPosition(position);
|
||||
|
||||
if (this.yaw != yaw) {
|
||||
moveEntityDeltaPacket.getFlags().add(MoveEntityDeltaPacket.Flag.HAS_YAW);
|
||||
moveEntityDeltaPacket.setYaw(yaw);
|
||||
this.yaw = yaw;
|
||||
}
|
||||
if (this.pitch != pitch) {
|
||||
moveEntityDeltaPacket.getFlags().add(MoveEntityDeltaPacket.Flag.HAS_PITCH);
|
||||
moveEntityDeltaPacket.setPitch(pitch);
|
||||
this.pitch = pitch;
|
||||
}
|
||||
if (this.headYaw != headYaw) {
|
||||
moveEntityDeltaPacket.getFlags().add(MoveEntityDeltaPacket.Flag.HAS_HEAD_YAW);
|
||||
moveEntityDeltaPacket.setHeadYaw(headYaw);
|
||||
this.headYaw = headYaw;
|
||||
}
|
||||
|
||||
if (!moveEntityDeltaPacket.getFlags().isEmpty()) {
|
||||
session.sendUpstreamPacket(moveEntityDeltaPacket);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 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 (getFlag(EntityFlag.HAS_GRAVITY)) {
|
||||
switch (definition.entityType()) {
|
||||
case THROWN_POTION:
|
||||
return 0.05f;
|
||||
case THROWN_EXP_BOTTLE:
|
||||
return 0.07f;
|
||||
case FIREBALL:
|
||||
case SHULKER_BULLET:
|
||||
return 0;
|
||||
case SNOWBALL:
|
||||
case THROWN_EGG:
|
||||
case THROWN_ENDERPEARL:
|
||||
return 0.03f;
|
||||
case LLAMA_SPIT:
|
||||
return 0.06f;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the drag that should be multiplied to the entity's motion
|
||||
*/
|
||||
protected float getDrag() {
|
||||
if (isInWater()) {
|
||||
return 0.8f;
|
||||
} else {
|
||||
switch (definition.entityType()) {
|
||||
case THROWN_POTION:
|
||||
case THROWN_EXP_BOTTLE:
|
||||
case SNOWBALL:
|
||||
case THROWN_EGG:
|
||||
case THROWN_ENDERPEARL:
|
||||
case LLAMA_SPIT:
|
||||
return 0.99f;
|
||||
case FIREBALL:
|
||||
case SMALL_FIREBALL:
|
||||
case DRAGON_FIREBALL:
|
||||
return 0.95f;
|
||||
case SHULKER_BULLET:
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return true if this entity is currently in water.
|
||||
*/
|
||||
protected boolean isInWater() {
|
||||
int block = session.getConnector().getWorldManager().getBlockAt(session, position.toInt());
|
||||
return BlockStateValues.getWaterLevel(block) != -1;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean despawnEntity() {
|
||||
if (definition.entityType() == EntityType.THROWN_ENDERPEARL) {
|
||||
LevelEventPacket particlePacket = new LevelEventPacket();
|
||||
particlePacket.setType(LevelEventType.PARTICLE_TELEPORT);
|
||||
particlePacket.setPosition(position);
|
||||
session.sendUpstreamPacket(particlePacket);
|
||||
}
|
||||
return super.despawnEntity();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void moveRelative(double relX, double relY, double relZ, float yaw, float pitch, float headYaw, boolean isOnGround) {
|
||||
moveAbsoluteImmediate(lastJavaPosition.add(relX, relY, relZ), yaw, pitch, headYaw, isOnGround, false);
|
||||
lastJavaPosition = position;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void moveAbsolute(Vector3f position, float yaw, float pitch, float headYaw, boolean isOnGround, boolean teleported) {
|
||||
moveAbsoluteImmediate(position, yaw, pitch, headYaw, isOnGround, teleported);
|
||||
lastJavaPosition = position;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,77 @@
|
|||
/*
|
||||
* Copyright (c) 2019-2021 GeyserMC. http://geysermc.org
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*
|
||||
* @author GeyserMC
|
||||
* @link https://github.com/GeyserMC/Geyser
|
||||
*/
|
||||
|
||||
package org.geysermc.connector.entity;
|
||||
|
||||
import com.nukkitx.math.vector.Vector3f;
|
||||
import com.nukkitx.protocol.bedrock.data.entity.EntityFlag;
|
||||
import org.geysermc.connector.network.session.GeyserSession;
|
||||
|
||||
import java.util.UUID;
|
||||
|
||||
/**
|
||||
* Used as a class for any projectile entity that looks like an item
|
||||
*/
|
||||
public class ThrowableItemEntity extends ThrowableEntity {
|
||||
/**
|
||||
* Number of ticks since the entity was spawned by the Java server
|
||||
*/
|
||||
private int age;
|
||||
private boolean invisible;
|
||||
|
||||
public ThrowableItemEntity(GeyserSession session, long entityId, long geyserId, UUID uuid, EntityDefinition<?> definition, Vector3f position, Vector3f motion, float yaw, float pitch, float headYaw) {
|
||||
super(session, entityId, geyserId, uuid, definition, position, motion, yaw, pitch, headYaw);
|
||||
setFlag(EntityFlag.INVISIBLE, true);
|
||||
invisible = false;
|
||||
}
|
||||
|
||||
private void checkVisibility() {
|
||||
if (invisible != getFlag(EntityFlag.INVISIBLE)) {
|
||||
if (!invisible) {
|
||||
Vector3f playerPos = session.getPlayerEntity().getPosition();
|
||||
// Prevent projectiles from blocking the player's screen
|
||||
if (age >= 4 || position.distanceSquared(playerPos) > 16) {
|
||||
setFlag(EntityFlag.INVISIBLE, false);
|
||||
updateBedrockMetadata();
|
||||
}
|
||||
} else {
|
||||
setFlag(EntityFlag.INVISIBLE, true);
|
||||
updateBedrockMetadata();
|
||||
}
|
||||
}
|
||||
age++;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void tick() {
|
||||
checkVisibility();
|
||||
super.tick();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void setInvisible(boolean value) {
|
||||
invisible = value;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,70 @@
|
|||
/*
|
||||
* Copyright (c) 2019-2021 GeyserMC. http://geysermc.org
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*
|
||||
* @author GeyserMC
|
||||
* @link https://github.com/GeyserMC/Geyser
|
||||
*/
|
||||
|
||||
package org.geysermc.connector.entity;
|
||||
|
||||
import com.github.steveice10.mc.protocol.data.game.entity.metadata.EntityMetadata;
|
||||
import com.github.steveice10.mc.protocol.data.game.entity.metadata.ItemStack;
|
||||
import com.github.steveice10.opennbt.tag.builtin.StringTag;
|
||||
import com.github.steveice10.opennbt.tag.builtin.Tag;
|
||||
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.GeyserConnector;
|
||||
import org.geysermc.connector.network.session.GeyserSession;
|
||||
import org.geysermc.connector.network.translators.item.Potion;
|
||||
import org.geysermc.connector.registry.type.ItemMapping;
|
||||
|
||||
import java.util.EnumSet;
|
||||
import java.util.UUID;
|
||||
|
||||
public class ThrownPotionEntity extends ThrowableItemEntity {
|
||||
private static final EnumSet<Potion> NON_ENCHANTED_POTIONS = EnumSet.of(Potion.WATER, Potion.MUNDANE, Potion.THICK, Potion.AWKWARD);
|
||||
|
||||
public ThrownPotionEntity(GeyserSession session, long entityId, long geyserId, UUID uuid, EntityDefinition<?> definition, Vector3f position, Vector3f motion, float yaw, float pitch, float headYaw) {
|
||||
super(session, entityId, geyserId, uuid, definition, position, motion, yaw, pitch, headYaw);
|
||||
}
|
||||
|
||||
public void setPotion(EntityMetadata<ItemStack, ?> entityMetadata) {
|
||||
ItemStack itemStack = entityMetadata.getValue();
|
||||
ItemMapping mapping = session.getItemMappings().getMapping(itemStack);
|
||||
if (mapping.getJavaIdentifier().endsWith("potion") && itemStack.getNbt() != null) {
|
||||
Tag potionTag = itemStack.getNbt().get("Potion");
|
||||
if (potionTag instanceof StringTag) {
|
||||
Potion potion = Potion.getByJavaIdentifier(((StringTag) potionTag).getValue());
|
||||
if (potion != null) {
|
||||
dirtyMetadata.put(EntityData.POTION_AUX_VALUE, potion.getBedrockId());
|
||||
setFlag(EntityFlag.ENCHANTED, !NON_ENCHANTED_POTIONS.contains(potion));
|
||||
} else {
|
||||
dirtyMetadata.put(EntityData.POTION_AUX_VALUE, 0);
|
||||
GeyserConnector.getInstance().getLogger().debug("Unknown java potion: " + potionTag.getValue());
|
||||
}
|
||||
}
|
||||
|
||||
boolean isLingering = mapping.getJavaIdentifier().equals("minecraft:lingering_potion");
|
||||
setFlag(EntityFlag.LINGERING, isLingering);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,33 @@
|
|||
/*
|
||||
* Copyright (c) 2019-2021 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;
|
||||
|
||||
/**
|
||||
* Implemented onto anything that should have code ran every Minecraft tick - 50 milliseconds.
|
||||
*/
|
||||
public interface Tickable {
|
||||
void tick();
|
||||
}
|
||||
|
|
@ -0,0 +1,59 @@
|
|||
/*
|
||||
* Copyright (c) 2019-2021 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.type.IntEntityMetadata;
|
||||
import com.nukkitx.math.vector.Vector3f;
|
||||
import com.nukkitx.protocol.bedrock.data.entity.EntityData;
|
||||
import org.geysermc.connector.network.session.GeyserSession;
|
||||
import org.geysermc.connector.network.translators.item.TippedArrowPotion;
|
||||
|
||||
import java.util.UUID;
|
||||
|
||||
/**
|
||||
* Internally this is known as TippedArrowEntity but is used with tipped arrows and normal arrows
|
||||
*/
|
||||
public class TippedArrowEntity extends AbstractArrowEntity {
|
||||
|
||||
public TippedArrowEntity(GeyserSession session, long entityId, long geyserId, UUID uuid, EntityDefinition<?> definition, Vector3f position, Vector3f motion, float yaw, float pitch, float headYaw) {
|
||||
super(session, entityId, geyserId, uuid, definition, position, motion, yaw, pitch, headYaw);
|
||||
}
|
||||
|
||||
public void setPotionEffectColor(IntEntityMetadata entityMetadata) {
|
||||
int potionColor = entityMetadata.getPrimitiveValue();
|
||||
// -1 means no color
|
||||
if (potionColor == -1) {
|
||||
dirtyMetadata.put(EntityData.CUSTOM_DISPLAY, 0);
|
||||
} else {
|
||||
TippedArrowPotion potion = TippedArrowPotion.getByJavaColor(potionColor);
|
||||
if (potion != null && potion.getJavaColor() != -1) {
|
||||
dirtyMetadata.put(EntityData.CUSTOM_DISPLAY, (byte) potion.getBedrockId());
|
||||
} else {
|
||||
dirtyMetadata.put(EntityData.CUSTOM_DISPLAY, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,38 @@
|
|||
/*
|
||||
* Copyright (c) 2019-2021 GeyserMC. http://geysermc.org
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*
|
||||
* @author GeyserMC
|
||||
* @link https://github.com/GeyserMC/Geyser
|
||||
*/
|
||||
|
||||
package org.geysermc.connector.entity;
|
||||
|
||||
import com.nukkitx.math.vector.Vector3f;
|
||||
import org.geysermc.connector.network.session.GeyserSession;
|
||||
|
||||
import java.util.UUID;
|
||||
|
||||
public class TridentEntity extends AbstractArrowEntity {
|
||||
|
||||
public TridentEntity(GeyserSession session, long entityId, long geyserId, UUID uuid, EntityDefinition<?> definition, Vector3f position, Vector3f motion, float yaw, float pitch, float headYaw) {
|
||||
super(session, entityId, geyserId, uuid, definition, position, motion, yaw, pitch, headYaw);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,58 @@
|
|||
/*
|
||||
* Copyright (c) 2019-2021 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.type.BooleanEntityMetadata;
|
||||
import com.nukkitx.math.vector.Vector3f;
|
||||
import org.geysermc.connector.network.session.GeyserSession;
|
||||
|
||||
import java.util.UUID;
|
||||
|
||||
public class WitherSkullEntity extends ItemedFireballEntity {
|
||||
private boolean isCharged;
|
||||
|
||||
public WitherSkullEntity(GeyserSession session, long entityId, long geyserId, UUID uuid, EntityDefinition<?> definition, Vector3f position, Vector3f motion, float yaw, float pitch, float headYaw) {
|
||||
super(session, entityId, geyserId, uuid, definition, position, motion, yaw, pitch, headYaw);
|
||||
|
||||
this.futureTicks = 1;
|
||||
}
|
||||
|
||||
public void setDangerous(BooleanEntityMetadata entityMetadata) {
|
||||
boolean newDangerous = entityMetadata.getPrimitiveValue();
|
||||
if (newDangerous != isCharged) {
|
||||
isCharged = newDangerous;
|
||||
// Is an entirely new entity in Bedrock but just a metadata type in Java
|
||||
definition = isCharged ? EntityDefinitions.WITHER_SKULL_DANGEROUS : EntityDefinitions.WITHER_SKULL;
|
||||
despawnEntity();
|
||||
spawnEntity();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected float getDrag() {
|
||||
return isCharged ? 0.73f : super.getDrag();
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,79 @@
|
|||
/*
|
||||
* Copyright (c) 2019-2021 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.attribute;
|
||||
|
||||
import com.nukkitx.protocol.bedrock.data.AttributeData;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Getter;
|
||||
|
||||
@Getter
|
||||
@AllArgsConstructor
|
||||
public enum GeyserAttributeType {
|
||||
|
||||
// Universal Attributes
|
||||
FOLLOW_RANGE("minecraft:generic.follow_range", "minecraft:follow_range", 0f, 2048f, 32f),
|
||||
KNOCKBACK_RESISTANCE("minecraft:generic.knockback_resistance", "minecraft:knockback_resistance", 0f, 1f, 0f),
|
||||
MOVEMENT_SPEED("minecraft:generic.movement_speed", "minecraft:movement", 0f, 1024f, 0.1f),
|
||||
FLYING_SPEED("minecraft:generic.flying_speed", "minecraft:movement", 0.0f, 1024.0f, 0.4000000059604645f),
|
||||
ATTACK_DAMAGE("minecraft:generic.attack_damage", "minecraft:attack_damage", 0f, 2048f, 1f),
|
||||
HORSE_JUMP_STRENGTH("minecraft:horse.jump_strength", "minecraft:horse.jump_strength", 0.0f, 2.0f, 0.7f),
|
||||
LUCK("minecraft:generic.luck", "minecraft:luck", -1024f, 1024f, 0f),
|
||||
|
||||
// Java Attributes
|
||||
ARMOR("minecraft:generic.armor", null, 0f, 30f, 0f),
|
||||
ARMOR_TOUGHNESS("minecraft:generic.armor_toughness", null, 0F, 20f, 0f),
|
||||
ATTACK_KNOCKBACK("minecraft:generic.attack_knockback", null, 1.5f, Float.MAX_VALUE, 0f),
|
||||
ATTACK_SPEED("minecraft:generic.attack_speed", null, 0f, 1024f, 4f),
|
||||
MAX_HEALTH("minecraft:generic.max_health", null, 0f, 1024f, 20f),
|
||||
|
||||
// Bedrock Attributes
|
||||
ABSORPTION(null, "minecraft:absorption", 0f, Float.MAX_VALUE, 0f),
|
||||
EXHAUSTION(null, "minecraft:player.exhaustion", 0f, 5f, 0f),
|
||||
EXPERIENCE(null, "minecraft:player.experience", 0f, 1f, 0f),
|
||||
EXPERIENCE_LEVEL(null, "minecraft:player.level", 0f, 24791.00f, 0f),
|
||||
HEALTH(null, "minecraft:health", 0f, 1024f, 20f),
|
||||
HUNGER(null, "minecraft:player.hunger", 0f, 20f, 20f),
|
||||
SATURATION(null, "minecraft:player.saturation", 0f, 20f, 20f);
|
||||
|
||||
private final String javaIdentifier;
|
||||
private final String bedrockIdentifier;
|
||||
|
||||
private final float minimum;
|
||||
private final float maximum;
|
||||
private final float defaultValue;
|
||||
|
||||
public AttributeData getAttribute(float value) {
|
||||
return getAttribute(value, maximum);
|
||||
}
|
||||
|
||||
public AttributeData getAttribute(float value, float maximum) {
|
||||
if (bedrockIdentifier == null) {
|
||||
return null;
|
||||
}
|
||||
// Minimum, maximum, and default values are hardcoded on Java Edition, whereas controlled by the server on Bedrock
|
||||
return new AttributeData(bedrockIdentifier, minimum, maximum, value, defaultValue);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,39 @@
|
|||
/*
|
||||
* Copyright (c) 2019-2021 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.factory;
|
||||
|
||||
import com.nukkitx.math.vector.Vector3f;
|
||||
import org.geysermc.connector.entity.Entity;
|
||||
import org.geysermc.connector.entity.EntityDefinition;
|
||||
import org.geysermc.connector.network.session.GeyserSession;
|
||||
|
||||
import java.util.UUID;
|
||||
|
||||
@FunctionalInterface
|
||||
public interface BaseEntityFactory<T extends Entity> extends EntityFactory<T> {
|
||||
|
||||
T create(GeyserSession session, long javaId, long bedrockId, UUID uuid, EntityDefinition<?> definition, Vector3f position, Vector3f motion, float yaw, float pitch, float headYaw);
|
||||
}
|
||||
|
|
@ -0,0 +1,31 @@
|
|||
/*
|
||||
* Copyright (c) 2019-2021 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.factory;
|
||||
|
||||
import org.geysermc.connector.entity.Entity;
|
||||
|
||||
public interface EntityFactory<T extends Entity> {
|
||||
}
|
||||
|
|
@ -0,0 +1,36 @@
|
|||
/*
|
||||
* Copyright (c) 2019-2021 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.factory;
|
||||
|
||||
import com.nukkitx.math.vector.Vector3f;
|
||||
import org.geysermc.connector.entity.ExpOrbEntity;
|
||||
import org.geysermc.connector.network.session.GeyserSession;
|
||||
|
||||
@FunctionalInterface
|
||||
public interface ExperienceOrbEntityFactory extends EntityFactory<ExpOrbEntity> {
|
||||
|
||||
ExpOrbEntity create(GeyserSession session, int amount, long entityId, long geyserId, Vector3f position);
|
||||
}
|
||||
|
|
@ -0,0 +1,38 @@
|
|||
/*
|
||||
* Copyright (c) 2019-2021 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.factory;
|
||||
|
||||
import com.nukkitx.math.vector.Vector3f;
|
||||
import org.geysermc.connector.entity.PaintingEntity;
|
||||
import org.geysermc.connector.network.session.GeyserSession;
|
||||
import org.geysermc.connector.utils.PaintingType;
|
||||
|
||||
import java.util.UUID;
|
||||
|
||||
public interface PaintingEntityFactory extends EntityFactory<PaintingEntity> {
|
||||
|
||||
PaintingEntity create(GeyserSession session, long entityId, long geyserId, UUID uuid, Vector3f position, PaintingType paintingName, int direction);
|
||||
}
|
||||
|
|
@ -0,0 +1,45 @@
|
|||
/*
|
||||
* Copyright (c) 2019-2021 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.nukkitx.math.vector.Vector3f;
|
||||
import com.nukkitx.protocol.bedrock.data.entity.EntityFlag;
|
||||
import org.geysermc.connector.entity.EntityDefinition;
|
||||
import org.geysermc.connector.network.session.GeyserSession;
|
||||
|
||||
import java.util.UUID;
|
||||
|
||||
public class AbstractFishEntity extends WaterEntity {
|
||||
|
||||
public AbstractFishEntity(GeyserSession session, long entityId, long geyserId, UUID uuid, EntityDefinition<?> definition, Vector3f position, Vector3f motion, float yaw, float pitch, float headYaw) {
|
||||
super(session, entityId, geyserId, uuid, definition, position, motion, yaw, pitch, headYaw);
|
||||
|
||||
setFlag(EntityFlag.CAN_SWIM, true);
|
||||
setFlag(EntityFlag.BREATHING, true);
|
||||
setFlag(EntityFlag.CAN_CLIMB, false);
|
||||
setFlag(EntityFlag.HAS_GRAVITY, false);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,70 @@
|
|||
/*
|
||||
* Copyright (c) 2019-2021 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.type.BooleanEntityMetadata;
|
||||
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.EntityDefinition;
|
||||
import org.geysermc.connector.network.session.GeyserSession;
|
||||
|
||||
import java.util.UUID;
|
||||
|
||||
public class AgeableEntity extends CreatureEntity {
|
||||
|
||||
public AgeableEntity(GeyserSession session, long entityId, long geyserId, UUID uuid, EntityDefinition<?> definition, Vector3f position, Vector3f motion, float yaw, float pitch, float headYaw) {
|
||||
super(session, entityId, geyserId, uuid, definition, position, motion, yaw, pitch, headYaw);
|
||||
}
|
||||
|
||||
public void setBaby(BooleanEntityMetadata entityMetadata) {
|
||||
boolean isBaby = entityMetadata.getPrimitiveValue();
|
||||
dirtyMetadata.put(EntityData.SCALE, isBaby ? getBabySize() : getAdultSize());
|
||||
setFlag(EntityFlag.BABY, isBaby);
|
||||
|
||||
// TODO save this?
|
||||
dirtyMetadata.put(EntityData.BOUNDING_BOX_HEIGHT, definition.height() * (isBaby ? getBabySize() : getAdultSize()));
|
||||
dirtyMetadata.put(EntityData.BOUNDING_BOX_WIDTH, definition.width() * (isBaby ? getBabySize() : getAdultSize()));
|
||||
}
|
||||
|
||||
/**
|
||||
* The scale that should be used when this entity is not a baby.
|
||||
*/
|
||||
protected float getAdultSize() {
|
||||
return 1f;
|
||||
}
|
||||
|
||||
/**
|
||||
* The scale that should be used when this entity is a baby.
|
||||
*/
|
||||
protected float getBabySize() {
|
||||
return 0.55f;
|
||||
}
|
||||
|
||||
public boolean isBaby() {
|
||||
return getFlag(EntityFlag.BABY);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,39 @@
|
|||
/*
|
||||
* Copyright (c) 2019-2021 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.nukkitx.math.vector.Vector3f;
|
||||
import org.geysermc.connector.entity.EntityDefinition;
|
||||
import org.geysermc.connector.network.session.GeyserSession;
|
||||
|
||||
import java.util.UUID;
|
||||
|
||||
public class AmbientEntity extends MobEntity {
|
||||
|
||||
public AmbientEntity(GeyserSession session, long entityId, long geyserId, UUID uuid, EntityDefinition<?> definition, Vector3f position, Vector3f motion, float yaw, float pitch, float headYaw) {
|
||||
super(session, entityId, geyserId, uuid, definition, position, motion, yaw, pitch, headYaw);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,433 @@
|
|||
/*
|
||||
* Copyright (c) 2019-2021 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.github.steveice10.mc.protocol.data.game.entity.metadata.Rotation;
|
||||
import com.github.steveice10.mc.protocol.data.game.entity.metadata.type.ByteEntityMetadata;
|
||||
import com.nukkitx.math.vector.Vector3f;
|
||||
import com.nukkitx.protocol.bedrock.data.entity.EntityData;
|
||||
import com.nukkitx.protocol.bedrock.data.entity.EntityFlag;
|
||||
import com.nukkitx.protocol.bedrock.data.inventory.ItemData;
|
||||
import com.nukkitx.protocol.bedrock.packet.MoveEntityAbsolutePacket;
|
||||
import lombok.Getter;
|
||||
import net.kyori.adventure.text.Component;
|
||||
import org.geysermc.connector.entity.EntityDefinition;
|
||||
import org.geysermc.connector.entity.EntityDefinitions;
|
||||
import org.geysermc.connector.entity.LivingEntity;
|
||||
import org.geysermc.connector.network.session.GeyserSession;
|
||||
|
||||
import java.util.Optional;
|
||||
import java.util.UUID;
|
||||
|
||||
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;
|
||||
|
||||
/**
|
||||
* On Java Edition, armor stands always show their name. Invisibility hides the name on Bedrock.
|
||||
* By having a second entity, we can allow an invisible entity with the name tag.
|
||||
* (This lets armor on armor stands still show)
|
||||
*/
|
||||
private ArmorStandEntity secondEntity = null;
|
||||
/**
|
||||
* Whether this is the primary armor stand that holds the armor and not the name tag.
|
||||
*/
|
||||
private boolean primaryEntity = true;
|
||||
/**
|
||||
* Whether the entity's position must be updated to included the offset.
|
||||
*
|
||||
* This should be true when the Java server marks the armor stand as invisible, but we shrink the entity
|
||||
* to allow the nametag to appear. Basically:
|
||||
* - Is visible: this is irrelevant (false)
|
||||
* - Has armor, no name: false
|
||||
* - Has armor, has name: false, with a second entity
|
||||
* - No armor, no name: false
|
||||
* - No armor, yes name: true
|
||||
*/
|
||||
private boolean positionRequiresOffset = false;
|
||||
/**
|
||||
* Whether we should update the position of this armor stand after metadata updates.
|
||||
*/
|
||||
private boolean positionUpdateRequired = false;
|
||||
|
||||
public ArmorStandEntity(GeyserSession session, long entityId, long geyserId, UUID uuid, EntityDefinition<?> definition, Vector3f position, Vector3f motion, float yaw, float pitch, float headYaw) {
|
||||
super(session, entityId, geyserId, uuid, definition, position, motion, yaw, pitch, headYaw);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void spawnEntity() {
|
||||
this.pitch = yaw;
|
||||
this.headYaw = yaw;
|
||||
super.spawnEntity();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean despawnEntity() {
|
||||
if (secondEntity != null) {
|
||||
secondEntity.despawnEntity();
|
||||
}
|
||||
return super.despawnEntity();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void moveRelative(double relX, double relY, double relZ, float yaw, float pitch, float headYaw, boolean isOnGround) {
|
||||
if (secondEntity != null) {
|
||||
secondEntity.moveRelative(relX, relY, relZ, yaw, pitch, headYaw, isOnGround);
|
||||
}
|
||||
super.moveRelative(relX, relY, relZ, yaw, pitch, headYaw, isOnGround);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void moveAbsolute(Vector3f position, float yaw, float pitch, float headYaw, boolean isOnGround, boolean teleported) {
|
||||
if (secondEntity != null) {
|
||||
secondEntity.moveAbsolute(applyOffsetToPosition(position), yaw, pitch, headYaw, isOnGround, teleported);
|
||||
} else if (positionRequiresOffset) {
|
||||
// Fake the height to be above where it is so the nametag appears in the right location for invisible non-marker armour stands
|
||||
position = applyOffsetToPosition(position);
|
||||
}
|
||||
|
||||
super.moveAbsolute(position, yaw, yaw, yaw, isOnGround, teleported);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setDisplayName(EntityMetadata<Optional<Component>, ?> entityMetadata) {
|
||||
super.setDisplayName(entityMetadata);
|
||||
updateSecondEntityStatus(false);
|
||||
}
|
||||
|
||||
public void setArmorStandFlags(ByteEntityMetadata entityMetadata) {
|
||||
byte xd = entityMetadata.getPrimitiveValue();
|
||||
|
||||
// isSmall
|
||||
boolean newIsSmall = (xd & 0x01) == 0x01;
|
||||
if (newIsSmall != isSmall) {
|
||||
if (positionRequiresOffset) {
|
||||
// Fix new inconsistency with offset
|
||||
this.position = fixOffsetForSize(position, newIsSmall);
|
||||
positionUpdateRequired = true;
|
||||
}
|
||||
|
||||
isSmall = newIsSmall;
|
||||
if (!isMarker) {
|
||||
toggleSmallStatus();
|
||||
}
|
||||
}
|
||||
|
||||
// setMarker
|
||||
boolean oldIsMarker = isMarker;
|
||||
isMarker = (xd & 0x10) == 0x10;
|
||||
if (oldIsMarker != isMarker) {
|
||||
if (isMarker) {
|
||||
dirtyMetadata.put(EntityData.BOUNDING_BOX_WIDTH, 0.0f);
|
||||
dirtyMetadata.put(EntityData.BOUNDING_BOX_HEIGHT, 0.0f);
|
||||
dirtyMetadata.put(EntityData.SCALE, 0f);
|
||||
} else {
|
||||
toggleSmallStatus();
|
||||
}
|
||||
|
||||
updateSecondEntityStatus(false);
|
||||
}
|
||||
|
||||
// The following values don't do anything on normal Bedrock.
|
||||
// But if given a resource pack, then we can use these values to control armor stand visual properties
|
||||
setFlag(EntityFlag.ANGRY, (xd & 0x04) != 0x04); // Has arms
|
||||
setFlag(EntityFlag.ADMIRING, (xd & 0x08) == 0x08); // Has no baseplate
|
||||
}
|
||||
|
||||
public void setHeadRotation(EntityMetadata<Rotation, ?> entityMetadata) {
|
||||
onRotationUpdate(EntityData.MARK_VARIANT, EntityFlag.INTERESTED, EntityFlag.CHARGED, EntityFlag.POWERED, entityMetadata.getValue());
|
||||
}
|
||||
|
||||
public void setBodyRotation(EntityMetadata<Rotation, ?> entityMetadata) {
|
||||
onRotationUpdate(EntityData.VARIANT, EntityFlag.IN_LOVE, EntityFlag.CELEBRATING, EntityFlag.CELEBRATING_SPECIAL, entityMetadata.getValue());
|
||||
}
|
||||
|
||||
public void setLeftArmRotation(EntityMetadata<Rotation, ?> entityMetadata) {
|
||||
onRotationUpdate(EntityData.TRADE_TIER, EntityFlag.CHARGING, EntityFlag.CRITICAL, EntityFlag.DANCING, entityMetadata.getValue());
|
||||
}
|
||||
|
||||
public void setRightArmRotation(EntityMetadata<Rotation, ?> entityMetadata) {
|
||||
onRotationUpdate(EntityData.MAX_TRADE_TIER, EntityFlag.ELDER, EntityFlag.EMOTING, EntityFlag.IDLING, entityMetadata.getValue());
|
||||
}
|
||||
|
||||
public void setLeftLegRotation(EntityMetadata<Rotation, ?> entityMetadata) {
|
||||
onRotationUpdate(EntityData.SKIN_ID, EntityFlag.IS_ILLAGER_CAPTAIN, EntityFlag.IS_IN_UI, EntityFlag.LINGERING, entityMetadata.getValue());
|
||||
}
|
||||
|
||||
public void setRightLegRotation(EntityMetadata<Rotation, ?> entityMetadata) {
|
||||
onRotationUpdate(EntityData.HURT_DIRECTION, EntityFlag.IS_PREGNANT, EntityFlag.SHEARED, EntityFlag.STALKING, entityMetadata.getValue());
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates rotation on the armor stand by hijacking other unused Bedrock entity data/flags.
|
||||
* Do note: as of recent Bedrock versions there is a custom entity data system that can be replaced with this,
|
||||
* but at this time there is no need to implement this.
|
||||
*
|
||||
* @param dataLeech the entity data to "leech" off of that stores a compressed version of the rotation
|
||||
* @param negativeXToggle the flag to set true if the X value of rotation is negative
|
||||
* @param negativeYToggle the flag to set true if the Y value of rotation is negative
|
||||
* @param negativeZToggle the flag to set true if the Z value of rotation is negative
|
||||
* @param rotation the Java rotation value
|
||||
*/
|
||||
private void onRotationUpdate(EntityData dataLeech, EntityFlag negativeXToggle, EntityFlag negativeYToggle, EntityFlag negativeZToggle, Rotation rotation) {
|
||||
// Indicate that rotation should be checked
|
||||
setFlag(EntityFlag.BRIBED, true);
|
||||
|
||||
int rotationX = getRotation(rotation.getPitch());
|
||||
int rotationY = getRotation(rotation.getYaw());
|
||||
int rotationZ = getRotation(rotation.getRoll());
|
||||
// The top bit acts like binary and determines if each rotation goes above 100
|
||||
// We don't do this for the negative values out of concerns of the number being too big
|
||||
int topBit = (Math.abs(rotationX) >= 100 ? 4 : 0) + (Math.abs(rotationY) >= 100 ? 2 : 0) + (Math.abs(rotationZ) >= 100 ? 1 : 0);
|
||||
int value = (topBit * 1000000) + ((Math.abs(rotationX) % 100) * 10000) + ((Math.abs(rotationY) % 100) * 100) + (Math.abs(rotationZ) % 100);
|
||||
dirtyMetadata.put(dataLeech, value);
|
||||
// Set the entity flags if a value is negative
|
||||
setFlag(negativeXToggle, rotationX < 0);
|
||||
setFlag(negativeYToggle, rotationY < 0);
|
||||
setFlag(negativeZToggle, rotationZ < 0);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateBedrockMetadata() {
|
||||
if (secondEntity != null) {
|
||||
secondEntity.updateBedrockMetadata();
|
||||
}
|
||||
super.updateBedrockMetadata();
|
||||
if (positionUpdateRequired) {
|
||||
positionUpdateRequired = false;
|
||||
updatePosition();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void setInvisible(boolean value) {
|
||||
// Check if the armour stand is invisible and store accordingly
|
||||
if (primaryEntity) {
|
||||
isInvisible = value;
|
||||
updateSecondEntityStatus(false);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setHelmet(ItemData helmet) {
|
||||
super.setHelmet(helmet);
|
||||
updateSecondEntityStatus(true);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setChestplate(ItemData chestplate) {
|
||||
super.setChestplate(chestplate);
|
||||
updateSecondEntityStatus(true);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setLeggings(ItemData leggings) {
|
||||
super.setLeggings(leggings);
|
||||
updateSecondEntityStatus(true);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setBoots(ItemData boots) {
|
||||
super.setBoots(boots);
|
||||
updateSecondEntityStatus(true);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setHand(ItemData hand) {
|
||||
super.setHand(hand);
|
||||
updateSecondEntityStatus(true);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setOffHand(ItemData offHand) {
|
||||
super.setOffHand(offHand);
|
||||
updateSecondEntityStatus(true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine if we need to load or unload the second entity.
|
||||
*
|
||||
* @param sendMetadata whether to send a metadata update after a change.
|
||||
*/
|
||||
private void updateSecondEntityStatus(boolean sendMetadata) {
|
||||
// A secondary entity always has to have the offset applied, so it remains invisible and the nametag shows.
|
||||
if (!primaryEntity) return;
|
||||
if (!isInvisible || isMarker) {
|
||||
// It is either impossible to show armor, or the armor stand isn't invisible. We good.
|
||||
setFlag(EntityFlag.INVISIBLE, false);
|
||||
updateOffsetRequirement(false);
|
||||
if (positionUpdateRequired) {
|
||||
positionUpdateRequired = false;
|
||||
updatePosition();
|
||||
}
|
||||
|
||||
if (secondEntity != null) {
|
||||
secondEntity.despawnEntity();
|
||||
secondEntity = null;
|
||||
}
|
||||
return;
|
||||
}
|
||||
boolean isNametagEmpty = nametag.isEmpty();
|
||||
if (!isNametagEmpty && (!helmet.equals(ItemData.AIR) || !chestplate.equals(ItemData.AIR) || !leggings.equals(ItemData.AIR)
|
||||
|| !boots.equals(ItemData.AIR) || !hand.equals(ItemData.AIR) || !offHand.equals(ItemData.AIR))) {
|
||||
// If the second entity exists, no need to recreate it.
|
||||
// We can't stuff this check above or else it'll fall into another else case and delete the second entity
|
||||
if (secondEntity != null) return;
|
||||
|
||||
// Create the second entity. It doesn't need to worry about the items, but it does need to worry about
|
||||
// the metadata as it will hold the name tag.
|
||||
secondEntity = new ArmorStandEntity(session, 0, session.getEntityCache().getNextEntityId().incrementAndGet(), null,
|
||||
EntityDefinitions.ARMOR_STAND, position, motion, yaw, pitch, headYaw);
|
||||
secondEntity.primaryEntity = false;
|
||||
if (!this.positionRequiresOffset) {
|
||||
// Ensure the offset is applied for the 0 scale
|
||||
secondEntity.position = secondEntity.applyOffsetToPosition(secondEntity.position);
|
||||
}
|
||||
// Copy metadata
|
||||
secondEntity.isSmall = isSmall;
|
||||
//secondEntity.getDirtyMetadata().putAll(dirtyMetadata); //TODO check
|
||||
secondEntity.flags.merge(this.flags);
|
||||
// Guarantee this copy is NOT invisible
|
||||
secondEntity.setFlag(EntityFlag.INVISIBLE, false);
|
||||
// Scale to 0 to show nametag
|
||||
secondEntity.getDirtyMetadata().put(EntityData.SCALE, 0.0f);
|
||||
// No bounding box as we don't want to interact with this entity
|
||||
secondEntity.getDirtyMetadata().put(EntityData.BOUNDING_BOX_WIDTH, 0.0f);
|
||||
secondEntity.getDirtyMetadata().put(EntityData.BOUNDING_BOX_HEIGHT, 0.0f);
|
||||
secondEntity.spawnEntity();
|
||||
|
||||
// Reset scale of the proper armor stand
|
||||
this.dirtyMetadata.put(EntityData.SCALE, isSmall ? 0.55f : 1f);
|
||||
// Set the proper armor stand to invisible to show armor
|
||||
setFlag(EntityFlag.INVISIBLE, true);
|
||||
// Update the position of the armor stand
|
||||
updateOffsetRequirement(false);
|
||||
} else if (isNametagEmpty) {
|
||||
// We can just make an invisible entity
|
||||
// Reset scale of the proper armor stand
|
||||
dirtyMetadata.put(EntityData.SCALE, isSmall ? 0.55f : 1f);
|
||||
// Set the proper armor stand to invisible to show armor
|
||||
setFlag(EntityFlag.INVISIBLE, true);
|
||||
// Update offset
|
||||
updateOffsetRequirement(false);
|
||||
|
||||
if (secondEntity != null) {
|
||||
secondEntity.despawnEntity();
|
||||
secondEntity = null;
|
||||
}
|
||||
} else {
|
||||
// Nametag is not empty and there is no armor
|
||||
// We don't need to make a new entity
|
||||
setFlag(EntityFlag.INVISIBLE, false);
|
||||
dirtyMetadata.put(EntityData.SCALE, 0.0f);
|
||||
// As the above is applied, we need an offset
|
||||
updateOffsetRequirement(true);
|
||||
|
||||
if (secondEntity != null) {
|
||||
secondEntity.despawnEntity();
|
||||
secondEntity = null;
|
||||
}
|
||||
}
|
||||
if (sendMetadata) {
|
||||
this.updateBedrockMetadata();
|
||||
}
|
||||
}
|
||||
|
||||
private int getRotation(float rotation) {
|
||||
rotation = rotation % 360f;
|
||||
if (rotation < -180f) {
|
||||
rotation += 360f;
|
||||
} else if (rotation >= 180f) {
|
||||
// 181 -> -179
|
||||
rotation = -(180 - (rotation - 180));
|
||||
}
|
||||
return (int) rotation;
|
||||
}
|
||||
|
||||
/**
|
||||
* If this armor stand is not a marker, set its bounding box size and scale.
|
||||
*/
|
||||
private void toggleSmallStatus() {
|
||||
dirtyMetadata.put(EntityData.BOUNDING_BOX_WIDTH, isSmall ? 0.25f : definition.width());
|
||||
dirtyMetadata.put(EntityData.BOUNDING_BOX_HEIGHT, isSmall ? 0.9875f : definition.height());
|
||||
dirtyMetadata.put(EntityData.SCALE, isSmall ? 0.55f : 1f);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the selected position with the position offset applied.
|
||||
*/
|
||||
private Vector3f applyOffsetToPosition(Vector3f position) {
|
||||
return position.add(0d, definition.height() * (isSmall ? 0.55d : 1d), 0d);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return an adjusted offset for the new small status.
|
||||
*/
|
||||
private Vector3f fixOffsetForSize(Vector3f position, boolean isNowSmall) {
|
||||
position = removeOffsetFromPosition(position);
|
||||
return position.add(0d, definition.height() * (isNowSmall ? 0.55d : 1d), 0d);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the selected position with the position offset removed.
|
||||
*/
|
||||
private Vector3f removeOffsetFromPosition(Vector3f position) {
|
||||
return position.sub(0d, definition.height() * (isSmall ? 0.55d : 1d), 0d);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the offset to a new value; if it changed, update the position, too.
|
||||
*/
|
||||
private void updateOffsetRequirement(boolean newValue) {
|
||||
if (newValue != positionRequiresOffset) {
|
||||
this.positionRequiresOffset = newValue;
|
||||
if (positionRequiresOffset) {
|
||||
this.position = applyOffsetToPosition(position);
|
||||
} else {
|
||||
this.position = removeOffsetFromPosition(position);
|
||||
}
|
||||
positionUpdateRequired = true;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates position without calling movement code.
|
||||
*/
|
||||
private void updatePosition() {
|
||||
MoveEntityAbsolutePacket moveEntityPacket = new MoveEntityAbsolutePacket();
|
||||
moveEntityPacket.setRuntimeEntityId(geyserId);
|
||||
moveEntityPacket.setPosition(position);
|
||||
moveEntityPacket.setRotation(Vector3f.from(yaw, yaw, yaw));
|
||||
moveEntityPacket.setOnGround(onGround);
|
||||
moveEntityPacket.setTeleported(false);
|
||||
session.sendUpstreamPacket(moveEntityPacket);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,46 @@
|
|||
/*
|
||||
* Copyright (c) 2019-2021 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.type.ByteEntityMetadata;
|
||||
import com.nukkitx.math.vector.Vector3f;
|
||||
import com.nukkitx.protocol.bedrock.data.entity.EntityFlag;
|
||||
import org.geysermc.connector.entity.EntityDefinition;
|
||||
import org.geysermc.connector.network.session.GeyserSession;
|
||||
|
||||
import java.util.UUID;
|
||||
|
||||
public class BatEntity extends AmbientEntity {
|
||||
|
||||
public BatEntity(GeyserSession session, long entityId, long geyserId, UUID uuid, EntityDefinition<?> definition, Vector3f position, Vector3f motion, float yaw, float pitch, float headYaw) {
|
||||
super(session, entityId, geyserId, uuid, definition, position, motion, yaw, pitch, headYaw);
|
||||
}
|
||||
|
||||
public void setBatFlags(ByteEntityMetadata entityMetadata) {
|
||||
byte xd = entityMetadata.getPrimitiveValue();
|
||||
setFlag(EntityFlag.RESTING, (xd & 0x01) == 0x01);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,39 @@
|
|||
/*
|
||||
* Copyright (c) 2019-2021 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.nukkitx.math.vector.Vector3f;
|
||||
import org.geysermc.connector.entity.EntityDefinition;
|
||||
import org.geysermc.connector.network.session.GeyserSession;
|
||||
|
||||
import java.util.UUID;
|
||||
|
||||
public class CreatureEntity extends MobEntity {
|
||||
|
||||
public CreatureEntity(GeyserSession session, long entityId, long geyserId, UUID uuid, EntityDefinition<?> definition, Vector3f position, Vector3f motion, float yaw, float pitch, float headYaw) {
|
||||
super(session, entityId, geyserId, uuid, definition, position, motion, yaw, pitch, headYaw);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,39 @@
|
|||
/*
|
||||
* Copyright (c) 2019-2021 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.nukkitx.math.vector.Vector3f;
|
||||
import org.geysermc.connector.entity.EntityDefinition;
|
||||
import org.geysermc.connector.network.session.GeyserSession;
|
||||
|
||||
import java.util.UUID;
|
||||
|
||||
public class FlyingEntity extends MobEntity {
|
||||
|
||||
public FlyingEntity(GeyserSession session, long entityId, long geyserId, UUID uuid, EntityDefinition<?> definition, Vector3f position, Vector3f motion, float yaw, float pitch, float headYaw) {
|
||||
super(session, entityId, geyserId, uuid, definition, position, motion, yaw, pitch, headYaw);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,38 @@
|
|||
/*
|
||||
* Copyright (c) 2019-2021 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.nukkitx.math.vector.Vector3f;
|
||||
import org.geysermc.connector.entity.EntityDefinition;
|
||||
import org.geysermc.connector.network.session.GeyserSession;
|
||||
|
||||
import java.util.UUID;
|
||||
|
||||
public class GlowSquidEntity extends SquidEntity {
|
||||
public GlowSquidEntity(GeyserSession session, long entityId, long geyserId, UUID uuid, EntityDefinition<?> definition, Vector3f position, Vector3f motion, float yaw, float pitch, float headYaw) {
|
||||
super(session, entityId, geyserId, uuid, definition, position, motion, yaw, pitch, headYaw);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,39 @@
|
|||
/*
|
||||
* Copyright (c) 2019-2021 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.nukkitx.math.vector.Vector3f;
|
||||
import org.geysermc.connector.entity.EntityDefinition;
|
||||
import org.geysermc.connector.network.session.GeyserSession;
|
||||
|
||||
import java.util.UUID;
|
||||
|
||||
public class GolemEntity extends CreatureEntity {
|
||||
|
||||
public GolemEntity(GeyserSession session, long entityId, long geyserId, UUID uuid, EntityDefinition<?> definition, Vector3f position, Vector3f motion, float yaw, float pitch, float headYaw) {
|
||||
super(session, entityId, geyserId, uuid, definition, position, motion, yaw, pitch, headYaw);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,45 @@
|
|||
/*
|
||||
* Copyright (c) 2019-2021 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.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.EntityDefinition;
|
||||
import org.geysermc.connector.network.session.GeyserSession;
|
||||
|
||||
import java.util.UUID;
|
||||
|
||||
public class IronGolemEntity extends GolemEntity {
|
||||
|
||||
public IronGolemEntity(GeyserSession session, long entityId, long geyserId, UUID uuid, EntityDefinition<?> definition, Vector3f position, Vector3f motion, float yaw, float pitch, float headYaw) {
|
||||
super(session, entityId, geyserId, uuid, definition, position, motion, yaw, pitch, headYaw);
|
||||
// Indicate that we should show cracks through a resource pack
|
||||
setFlag(EntityFlag.BRIBED, true);
|
||||
// Required, or else the overlay is black
|
||||
dirtyMetadata.put(EntityData.COLOR_2, (byte) 0);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,60 @@
|
|||
/*
|
||||
* Copyright (c) 2019-2021 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.nukkitx.math.vector.Vector3f;
|
||||
import com.nukkitx.protocol.bedrock.data.entity.EntityData;
|
||||
import org.geysermc.connector.entity.EntityDefinition;
|
||||
import org.geysermc.connector.network.session.GeyserSession;
|
||||
|
||||
import java.util.UUID;
|
||||
|
||||
public class MagmaCubeEntity extends SlimeEntity {
|
||||
|
||||
public MagmaCubeEntity(GeyserSession session, long entityId, long geyserId, UUID uuid, EntityDefinition<?> definition, Vector3f position, Vector3f motion, float yaw, float pitch, float headYaw) {
|
||||
super(session, entityId, geyserId, uuid, definition, position, motion, yaw, pitch, headYaw);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void moveRelative(double relX, double relY, double relZ, float yaw, float pitch, float headYaw, boolean isOnGround) {
|
||||
updateJump(isOnGround);
|
||||
super.moveRelative(relX, relY, relZ, yaw, pitch, headYaw, isOnGround);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void moveAbsolute(Vector3f position, float yaw, float pitch, float headYaw, boolean isOnGround, boolean teleported) {
|
||||
updateJump(isOnGround);
|
||||
super.moveAbsolute(position, yaw, pitch, headYaw, isOnGround, teleported);
|
||||
}
|
||||
|
||||
public void updateJump(boolean newOnGround) {
|
||||
if (newOnGround != onGround) {
|
||||
// Add the jumping effect to the magma cube
|
||||
dirtyMetadata.put(EntityData.CLIENT_EVENT, (byte) (newOnGround ? 1 : 2));
|
||||
updateBedrockMetadata();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,65 @@
|
|||
/*
|
||||
* Copyright (c) 2019-2021 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.type.ByteEntityMetadata;
|
||||
import com.nukkitx.math.vector.Vector3f;
|
||||
import com.nukkitx.protocol.bedrock.data.entity.EntityData;
|
||||
import com.nukkitx.protocol.bedrock.data.entity.EntityFlag;
|
||||
import lombok.Getter;
|
||||
import org.geysermc.connector.entity.EntityDefinition;
|
||||
import org.geysermc.connector.entity.LivingEntity;
|
||||
import org.geysermc.connector.network.session.GeyserSession;
|
||||
|
||||
import java.util.UUID;
|
||||
|
||||
public class MobEntity extends LivingEntity {
|
||||
/**
|
||||
* If another mob is holding this mob by a leash, this variable tracks their Bedrock entity ID.
|
||||
*/
|
||||
@Getter
|
||||
private long leashHolderBedrockId;
|
||||
|
||||
public MobEntity(GeyserSession session, long entityId, long geyserId, UUID uuid, EntityDefinition<?> definition, Vector3f position, Vector3f motion, float yaw, float pitch, float headYaw) {
|
||||
super(session, entityId, geyserId, uuid, definition, position, motion, yaw, pitch, headYaw);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void initializeMetadata() {
|
||||
super.initializeMetadata();
|
||||
setLeashHolderBedrockId(-1);
|
||||
}
|
||||
|
||||
public void setMobFlags(ByteEntityMetadata entityMetadata) {
|
||||
byte xd = entityMetadata.getPrimitiveValue();
|
||||
setFlag(EntityFlag.NO_AI, (xd & 0x01) == 0x01);
|
||||
}
|
||||
|
||||
public void setLeashHolderBedrockId(long bedrockId) {
|
||||
this.leashHolderBedrockId = bedrockId;
|
||||
dirtyMetadata.put(EntityData.LEASH_HOLDER_EID, bedrockId);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,45 @@
|
|||
/*
|
||||
* Copyright (c) 2019-2021 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.type.IntEntityMetadata;
|
||||
import com.nukkitx.math.vector.Vector3f;
|
||||
import com.nukkitx.protocol.bedrock.data.entity.EntityData;
|
||||
import org.geysermc.connector.entity.EntityDefinition;
|
||||
import org.geysermc.connector.network.session.GeyserSession;
|
||||
|
||||
import java.util.UUID;
|
||||
|
||||
public class SlimeEntity extends MobEntity {
|
||||
|
||||
public SlimeEntity(GeyserSession session, long entityId, long geyserId, UUID uuid, EntityDefinition<?> definition, Vector3f position, Vector3f motion, float yaw, float pitch, float headYaw) {
|
||||
super(session, entityId, geyserId, uuid, definition, position, motion, yaw, pitch, headYaw);
|
||||
}
|
||||
|
||||
public void setScale(IntEntityMetadata entityMetadata) {
|
||||
dirtyMetadata.put(EntityData.SCALE, 0.10f + entityMetadata.getPrimitiveValue());
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,47 @@
|
|||
/*
|
||||
* Copyright (c) 2019-2021 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.type.ByteEntityMetadata;
|
||||
import com.nukkitx.math.vector.Vector3f;
|
||||
import com.nukkitx.protocol.bedrock.data.entity.EntityFlag;
|
||||
import org.geysermc.connector.entity.EntityDefinition;
|
||||
import org.geysermc.connector.network.session.GeyserSession;
|
||||
|
||||
import java.util.UUID;
|
||||
|
||||
public class SnowGolemEntity extends GolemEntity {
|
||||
|
||||
public SnowGolemEntity(GeyserSession session, long entityId, long geyserId, UUID uuid, EntityDefinition<?> definition, Vector3f position, Vector3f motion, float yaw, float pitch, float headYaw) {
|
||||
super(session, entityId, geyserId, uuid, definition, position, motion, yaw, pitch, headYaw);
|
||||
}
|
||||
|
||||
public void setSnowGolemFlags(ByteEntityMetadata entityMetadata) {
|
||||
byte xd = entityMetadata.getPrimitiveValue();
|
||||
// Handle the visibility of the pumpkin
|
||||
setFlag(EntityFlag.SHEARED, (xd & 0x10) != 0x10);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,131 @@
|
|||
/*
|
||||
* Copyright (c) 2019-2021 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.nukkitx.math.vector.Vector3f;
|
||||
import com.nukkitx.protocol.bedrock.data.entity.EntityFlag;
|
||||
import com.nukkitx.protocol.bedrock.packet.MoveEntityDeltaPacket;
|
||||
import org.geysermc.connector.entity.EntityDefinition;
|
||||
import org.geysermc.connector.entity.Tickable;
|
||||
import org.geysermc.connector.network.session.GeyserSession;
|
||||
import org.geysermc.connector.network.translators.world.block.BlockStateValues;
|
||||
|
||||
import java.util.UUID;
|
||||
|
||||
public class SquidEntity extends WaterEntity implements Tickable {
|
||||
private float targetPitch;
|
||||
private float targetYaw;
|
||||
|
||||
private boolean inWater;
|
||||
|
||||
public SquidEntity(GeyserSession session, long entityId, long geyserId, UUID uuid, EntityDefinition<?> definition, Vector3f position, Vector3f motion, float yaw, float pitch, float headYaw) {
|
||||
super(session, entityId, geyserId, uuid, definition, position, motion, yaw, pitch, headYaw);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void tick() {
|
||||
boolean pitchChanged;
|
||||
boolean yawChanged;
|
||||
float oldPitch = pitch;
|
||||
if (inWater) {
|
||||
float oldYaw = yaw;
|
||||
pitch += (targetPitch - pitch) * 0.1f;
|
||||
yaw += (targetYaw - yaw) * 0.1f;
|
||||
yawChanged = oldYaw != yaw;
|
||||
} else {
|
||||
pitch += (-90 - pitch) * 0.02f;
|
||||
yawChanged = false;
|
||||
}
|
||||
pitchChanged = oldPitch != pitch;
|
||||
|
||||
if (pitchChanged || yawChanged) {
|
||||
MoveEntityDeltaPacket packet = new MoveEntityDeltaPacket();
|
||||
packet.setRuntimeEntityId(geyserId);
|
||||
|
||||
if (pitchChanged) {
|
||||
packet.getFlags().add(MoveEntityDeltaPacket.Flag.HAS_PITCH);
|
||||
packet.setPitch(pitch);
|
||||
}
|
||||
if (yawChanged) {
|
||||
packet.getFlags().add(MoveEntityDeltaPacket.Flag.HAS_YAW);
|
||||
packet.setYaw(yaw);
|
||||
}
|
||||
|
||||
session.sendUpstreamPacket(packet);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void moveRelative(double relX, double relY, double relZ, float yaw, float pitch, float headYaw, boolean isOnGround) {
|
||||
super.moveRelative(relX, relY, relZ, yaw, pitch, headYaw, isOnGround);
|
||||
checkInWater();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void moveAbsolute(Vector3f position, float yaw, float pitch, float headYaw, boolean isOnGround, boolean teleported) {
|
||||
super.moveAbsolute(position, yaw, pitch, headYaw, isOnGround, teleported);
|
||||
checkInWater();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setYaw(float yaw) {
|
||||
// Let the Java server control yaw when the squid is out of water
|
||||
if (!inWater) {
|
||||
this.yaw = yaw;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setPitch(float pitch) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setHeadYaw(float headYaw) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setMotion(Vector3f motion) {
|
||||
super.setMotion(motion);
|
||||
|
||||
double horizontalSpeed = Math.sqrt(motion.getX() * motion.getX() + motion.getZ() * motion.getZ());
|
||||
targetPitch = (float) Math.toDegrees(-Math.atan2(horizontalSpeed, motion.getY()));
|
||||
targetYaw = (float) Math.toDegrees(-Math.atan2(motion.getX(), motion.getZ()));
|
||||
}
|
||||
|
||||
@Override
|
||||
public Vector3f getBedrockRotation() {
|
||||
return Vector3f.from(pitch, yaw, yaw);
|
||||
}
|
||||
|
||||
private void checkInWater() {
|
||||
if (getFlag(EntityFlag.RIDING)) {
|
||||
inWater = false;
|
||||
} else {
|
||||
int block = session.getConnector().getWorldManager().getBlockAt(session, position.toInt());
|
||||
inWater = BlockStateValues.getWaterLevel(block) != -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,39 @@
|
|||
/*
|
||||
* Copyright (c) 2019-2021 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.nukkitx.math.vector.Vector3f;
|
||||
import org.geysermc.connector.entity.EntityDefinition;
|
||||
import org.geysermc.connector.network.session.GeyserSession;
|
||||
|
||||
import java.util.UUID;
|
||||
|
||||
public class WaterEntity extends CreatureEntity {
|
||||
|
||||
public WaterEntity(GeyserSession session, long entityId, long geyserId, UUID uuid, EntityDefinition<?> definition, Vector3f position, Vector3f motion, float yaw, float pitch, float headYaw) {
|
||||
super(session, entityId, geyserId, uuid, definition, position, motion, yaw, pitch, headYaw);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,51 @@
|
|||
/*
|
||||
* Copyright (c) 2019-2021 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.nukkitx.math.vector.Vector3f;
|
||||
import org.geysermc.connector.entity.EntityDefinition;
|
||||
import org.geysermc.connector.entity.living.AgeableEntity;
|
||||
import org.geysermc.connector.network.session.GeyserSession;
|
||||
import org.geysermc.connector.registry.type.ItemMapping;
|
||||
|
||||
import java.util.UUID;
|
||||
|
||||
public class AnimalEntity extends AgeableEntity {
|
||||
|
||||
public AnimalEntity(GeyserSession session, long entityId, long geyserId, UUID uuid, EntityDefinition<?> definition, Vector3f position, Vector3f motion, float yaw, float pitch, float headYaw) {
|
||||
super(session, entityId, geyserId, uuid, definition, position, motion, yaw, pitch, headYaw);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param javaIdentifierStripped the stripped Java identifier of the item that is potential breeding food. For example,
|
||||
* <code>wheat</code>.
|
||||
* @return true if this is a valid item to breed with for this animal.
|
||||
*/
|
||||
public boolean canEat(String javaIdentifierStripped, ItemMapping mapping) {
|
||||
// This is what it defaults to. OK.
|
||||
return javaIdentifierStripped.equals("wheat");
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,66 @@
|
|||
/*
|
||||
* Copyright (c) 2019-2021 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.type.BooleanEntityMetadata;
|
||||
import com.github.steveice10.mc.protocol.data.game.entity.metadata.type.IntEntityMetadata;
|
||||
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.EntityDefinition;
|
||||
import org.geysermc.connector.network.session.GeyserSession;
|
||||
import org.geysermc.connector.registry.type.ItemMapping;
|
||||
|
||||
import java.util.UUID;
|
||||
|
||||
public class AxolotlEntity extends AnimalEntity {
|
||||
public AxolotlEntity(GeyserSession session, long entityId, long geyserId, UUID uuid, EntityDefinition<?> definition, Vector3f position, Vector3f motion, float yaw, float pitch, float headYaw) {
|
||||
super(session, entityId, geyserId, uuid, definition, position, motion, yaw, pitch, headYaw);
|
||||
}
|
||||
|
||||
public void setVariant(IntEntityMetadata entityMetadata) {
|
||||
int variant = entityMetadata.getPrimitiveValue();
|
||||
switch (variant) {
|
||||
case 1 -> variant = 3; // Java - "Wild" (brown)
|
||||
case 3 -> variant = 1; // Java - cyan
|
||||
}
|
||||
dirtyMetadata.put(EntityData.VARIANT, variant);
|
||||
}
|
||||
|
||||
public void setPlayingDead(BooleanEntityMetadata entityMetadata) {
|
||||
setFlag(EntityFlag.PLAYING_DEAD, entityMetadata.getPrimitiveValue());
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean canEat(String javaIdentifierStripped, ItemMapping mapping) {
|
||||
return javaIdentifierStripped.equals("tropical_fish_bucket");
|
||||
}
|
||||
|
||||
@Override
|
||||
protected int getMaxAir() {
|
||||
return 6000;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,72 @@
|
|||
/*
|
||||
* Copyright (c) 2019-2021 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.type.ByteEntityMetadata;
|
||||
import com.github.steveice10.mc.protocol.data.game.entity.metadata.type.IntEntityMetadata;
|
||||
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.EntityDefinition;
|
||||
import org.geysermc.connector.network.session.GeyserSession;
|
||||
import org.geysermc.connector.registry.type.ItemMapping;
|
||||
|
||||
import java.util.UUID;
|
||||
|
||||
public class BeeEntity extends AnimalEntity {
|
||||
|
||||
public BeeEntity(GeyserSession session, long entityId, long geyserId, UUID uuid, EntityDefinition<?> definition, Vector3f position, Vector3f motion, float yaw, float pitch, float headYaw) {
|
||||
super(session, entityId, geyserId, uuid, definition, position, motion, yaw, pitch, headYaw);
|
||||
}
|
||||
|
||||
public void setBeeFlags(ByteEntityMetadata entityMetadata) {
|
||||
byte xd = entityMetadata.getPrimitiveValue();
|
||||
// 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
|
||||
dirtyMetadata.put(EntityData.MARK_VARIANT, (xd & 0x04) == 0x04 ? 1 : 0);
|
||||
// If the bee has nectar or not
|
||||
setFlag(EntityFlag.POWERED, (xd & 0x08) == 0x08);
|
||||
}
|
||||
|
||||
public void setAngerTime(IntEntityMetadata entityMetadata) {
|
||||
// Converting "anger time" to a boolean
|
||||
setFlag(EntityFlag.ANGRY, entityMetadata.getPrimitiveValue() > 0);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean canEat(String javaIdentifierStripped, ItemMapping mapping) {
|
||||
return session.getTagCache().isFlower(mapping);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,45 @@
|
|||
/*
|
||||
* Copyright (c) 2019-2021 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.nukkitx.math.vector.Vector3f;
|
||||
import org.geysermc.connector.entity.EntityDefinition;
|
||||
import org.geysermc.connector.network.session.GeyserSession;
|
||||
import org.geysermc.connector.registry.type.ItemMapping;
|
||||
|
||||
import java.util.UUID;
|
||||
|
||||
public class ChickenEntity extends AnimalEntity {
|
||||
|
||||
public ChickenEntity(GeyserSession session, long entityId, long geyserId, UUID uuid, EntityDefinition<?> definition, Vector3f position, Vector3f motion, float yaw, float pitch, float headYaw) {
|
||||
super(session, entityId, geyserId, uuid, definition, position, motion, yaw, pitch, headYaw);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean canEat(String javaIdentifierStripped, ItemMapping mapping) {
|
||||
return javaIdentifierStripped.contains("seeds");
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,61 @@
|
|||
/*
|
||||
* Copyright (c) 2019-2021 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.type.ByteEntityMetadata;
|
||||
import com.github.steveice10.mc.protocol.data.game.entity.metadata.type.IntEntityMetadata;
|
||||
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.EntityDefinition;
|
||||
import org.geysermc.connector.network.session.GeyserSession;
|
||||
import org.geysermc.connector.registry.type.ItemMapping;
|
||||
|
||||
import java.util.UUID;
|
||||
|
||||
public class FoxEntity extends AnimalEntity {
|
||||
|
||||
public FoxEntity(GeyserSession session, long entityId, long geyserId, UUID uuid, EntityDefinition<?> definition, Vector3f position, Vector3f motion, float yaw, float pitch, float headYaw) {
|
||||
super(session, entityId, geyserId, uuid, definition, position, motion, yaw, pitch, headYaw);
|
||||
}
|
||||
|
||||
public void setFoxVariant(IntEntityMetadata entityMetadata) {
|
||||
dirtyMetadata.put(EntityData.VARIANT, entityMetadata.getPrimitiveValue());
|
||||
}
|
||||
|
||||
public void setFoxFlags(ByteEntityMetadata entityMetadata) {
|
||||
byte xd = entityMetadata.getPrimitiveValue();
|
||||
setFlag(EntityFlag.SITTING, (xd & 0x01) == 0x01);
|
||||
setFlag(EntityFlag.SNEAKING, (xd & 0x04) == 0x04);
|
||||
setFlag(EntityFlag.INTERESTED, (xd & 0x08) == 0x08);
|
||||
setFlag(EntityFlag.SLEEPING, (xd & 0x20) == 0x20);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean canEat(String javaIdentifierStripped, ItemMapping mapping) {
|
||||
return session.getTagCache().isFoxFood(mapping);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,62 @@
|
|||
/*
|
||||
* Copyright (c) 2019-2021 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.Pose;
|
||||
import com.github.steveice10.mc.protocol.data.game.entity.metadata.type.BooleanEntityMetadata;
|
||||
import com.nukkitx.math.vector.Vector3f;
|
||||
import lombok.Getter;
|
||||
import org.geysermc.connector.entity.EntityDefinition;
|
||||
import org.geysermc.connector.network.session.GeyserSession;
|
||||
|
||||
import java.util.UUID;
|
||||
|
||||
public class GoatEntity extends AnimalEntity {
|
||||
private static final float LONG_JUMPING_HEIGHT = 1.3f * 0.7f;
|
||||
private static final float LONG_JUMPING_WIDTH = 0.9f * 0.7f;
|
||||
|
||||
@Getter
|
||||
private boolean isScreamer;
|
||||
|
||||
public GoatEntity(GeyserSession session, long entityId, long geyserId, UUID uuid, EntityDefinition<?> definition, Vector3f position, Vector3f motion, float yaw, float pitch, float headYaw) {
|
||||
super(session, entityId, geyserId, uuid, definition, position, motion, yaw, pitch, headYaw);
|
||||
}
|
||||
|
||||
public void setScreamer(BooleanEntityMetadata entityMetadata) {
|
||||
// Metadata not used in Bedrock Edition
|
||||
isScreamer = entityMetadata.getPrimitiveValue();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void setDimensions(Pose pose) {
|
||||
if (pose == Pose.LONG_JUMPING) {
|
||||
setBoundingBoxWidth(LONG_JUMPING_WIDTH);
|
||||
setBoundingBoxHeight(LONG_JUMPING_HEIGHT);
|
||||
} else {
|
||||
super.setDimensions(pose);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,60 @@
|
|||
/*
|
||||
* Copyright (c) 2019-2021 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.type.BooleanEntityMetadata;
|
||||
import com.nukkitx.math.vector.Vector3f;
|
||||
import com.nukkitx.protocol.bedrock.data.entity.EntityFlag;
|
||||
import org.geysermc.connector.entity.EntityDefinition;
|
||||
import org.geysermc.connector.network.session.GeyserSession;
|
||||
import org.geysermc.connector.registry.type.ItemMapping;
|
||||
import org.geysermc.connector.utils.DimensionUtils;
|
||||
|
||||
import java.util.UUID;
|
||||
|
||||
public class HoglinEntity extends AnimalEntity {
|
||||
private boolean isImmuneToZombification;
|
||||
|
||||
public HoglinEntity(GeyserSession session, long entityId, long geyserId, UUID uuid, EntityDefinition<?> definition, Vector3f position, Vector3f motion, float yaw, float pitch, float headYaw) {
|
||||
super(session, entityId, geyserId, uuid, definition, position, motion, yaw, pitch, headYaw);
|
||||
}
|
||||
|
||||
public void setImmuneToZombification(BooleanEntityMetadata entityMetadata) {
|
||||
// Apply shaking effect if not in the nether and zombification is possible
|
||||
this.isImmuneToZombification = entityMetadata.getPrimitiveValue();
|
||||
setFlag(EntityFlag.SHAKING, isShaking());
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean isShaking() {
|
||||
return (!isImmuneToZombification && !session.getDimension().equals(DimensionUtils.NETHER)) || super.isShaking();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean canEat(String javaIdentifierStripped, ItemMapping mapping) {
|
||||
return javaIdentifierStripped.equals("crimson_fungus");
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,39 @@
|
|||
/*
|
||||
* Copyright (c) 2019-2021 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.nukkitx.math.vector.Vector3f;
|
||||
import org.geysermc.connector.entity.EntityDefinition;
|
||||
import org.geysermc.connector.network.session.GeyserSession;
|
||||
|
||||
import java.util.UUID;
|
||||
|
||||
public class MooshroomEntity extends AnimalEntity {
|
||||
|
||||
public MooshroomEntity(GeyserSession session, long entityId, long geyserId, UUID uuid, EntityDefinition<?> definition, Vector3f position, Vector3f motion, float yaw, float pitch, float headYaw) {
|
||||
super(session, entityId, geyserId, uuid, definition, position, motion, yaw, pitch, headYaw);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,45 @@
|
|||
/*
|
||||
* Copyright (c) 2019-2021 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.nukkitx.math.vector.Vector3f;
|
||||
import org.geysermc.connector.entity.EntityDefinition;
|
||||
import org.geysermc.connector.network.session.GeyserSession;
|
||||
import org.geysermc.connector.registry.type.ItemMapping;
|
||||
|
||||
import java.util.UUID;
|
||||
|
||||
public class OcelotEntity extends AnimalEntity {
|
||||
|
||||
public OcelotEntity(GeyserSession session, long entityId, long geyserId, UUID uuid, EntityDefinition<?> definition, Vector3f position, Vector3f motion, float yaw, float pitch, float headYaw) {
|
||||
super(session, entityId, geyserId, uuid, definition, position, motion, yaw, pitch, headYaw);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean canEat(String javaIdentifierStripped, ItemMapping mapping) {
|
||||
return javaIdentifierStripped.equals("cod") || javaIdentifierStripped.equals("salmon");
|
||||
}
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue