Mirror von
https://github.com/GeyserMC/Geyser.git
synchronisiert 2024-09-08 20:43:04 +02:00
Merge remote-tracking branch 'origin/master' into floodgate-2.0
# Conflicts: # connector/src/main/java/org/geysermc/connector/dump/BootstrapDumpInfo.java # connector/src/main/java/org/geysermc/connector/dump/DumpInfo.java # connector/src/main/java/org/geysermc/connector/network/session/GeyserSession.java # connector/src/main/java/org/geysermc/connector/network/translators/java/JavaJoinGameTranslator.java # connector/src/main/java/org/geysermc/connector/utils/SettingsUtils.java
Dieser Commit ist enthalten in:
Commit
3b9674ac29
@ -25,7 +25,6 @@
|
||||
|
||||
package org.geysermc.connector.command.defaults;
|
||||
|
||||
import com.github.steveice10.mc.protocol.data.game.entity.metadata.Position;
|
||||
import com.github.steveice10.mc.protocol.data.game.entity.player.PlayerAction;
|
||||
import com.github.steveice10.mc.protocol.data.game.world.block.BlockFace;
|
||||
import com.github.steveice10.mc.protocol.packet.ingame.client.player.ClientPlayerActionPacket;
|
||||
@ -33,15 +32,12 @@ 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 {
|
||||
|
||||
private final GeyserConnector connector;
|
||||
|
||||
public OffhandCommand(GeyserConnector connector, String name, String description, String permission) {
|
||||
super(name, description, permission);
|
||||
|
||||
this.connector = connector;
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -50,7 +46,7 @@ public class OffhandCommand extends GeyserCommand {
|
||||
return;
|
||||
}
|
||||
|
||||
ClientPlayerActionPacket releaseItemPacket = new ClientPlayerActionPacket(PlayerAction.SWAP_HANDS, new Position(0,0,0),
|
||||
ClientPlayerActionPacket releaseItemPacket = new ClientPlayerActionPacket(PlayerAction.SWAP_HANDS, BlockUtils.POSITION_ZERO,
|
||||
BlockFace.DOWN);
|
||||
session.sendDownstreamPacket(releaseItemPacket);
|
||||
}
|
||||
|
@ -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.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();
|
||||
switch (value) {
|
||||
case "no-emotes":
|
||||
return NO_EMOTES;
|
||||
case "emotes-and-offhand":
|
||||
return EMOTES_AND_OFFHAND;
|
||||
default:
|
||||
return DISABLED;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -77,6 +77,8 @@ public interface GeyserConfiguration {
|
||||
|
||||
boolean isShowCoordinates();
|
||||
|
||||
EmoteOffhandWorkaroundOption getEmoteOffhandWorkaround();
|
||||
|
||||
String getDefaultLocale();
|
||||
|
||||
Path getFloodgateKeyPath();
|
||||
@ -138,6 +140,8 @@ public interface GeyserConfiguration {
|
||||
boolean isPasswordAuthentication();
|
||||
|
||||
boolean isUseProxyProtocol();
|
||||
|
||||
boolean isForwardHost();
|
||||
}
|
||||
|
||||
interface IUserAuthenticationInfo {
|
||||
|
@ -28,6 +28,7 @@ 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.databind.annotation.JsonDeserialize;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
import org.geysermc.connector.GeyserConnector;
|
||||
@ -100,6 +101,10 @@ public abstract class GeyserJacksonConfiguration implements GeyserConfiguration
|
||||
@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;
|
||||
|
||||
@ -197,6 +202,9 @@ public abstract class GeyserJacksonConfiguration implements GeyserConfiguration
|
||||
|
||||
@JsonProperty("use-proxy-protocol")
|
||||
private boolean useProxyProtocol = false;
|
||||
|
||||
@JsonProperty("forward-hostname")
|
||||
private boolean forwardHost = false;
|
||||
}
|
||||
|
||||
@Getter
|
||||
|
@ -27,8 +27,12 @@ package org.geysermc.connector.dump;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonIgnore;
|
||||
import com.github.steveice10.mc.protocol.MinecraftConstants;
|
||||
import com.google.common.hash.Hashing;
|
||||
import com.google.common.io.ByteSource;
|
||||
import com.google.common.io.Files;
|
||||
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;
|
||||
@ -40,6 +44,7 @@ import org.geysermc.connector.utils.FileUtils;
|
||||
import org.geysermc.floodgate.util.DeviceOs;
|
||||
import org.geysermc.floodgate.util.FloodgateConfigHolder;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.net.InetAddress;
|
||||
import java.net.InetSocketAddress;
|
||||
@ -56,6 +61,7 @@ public class DumpInfo {
|
||||
private Properties gitInfo;
|
||||
private final GeyserConfiguration config;
|
||||
private final Object floodgateConfig;
|
||||
private final HashInfo hashInfo;
|
||||
private final Object2IntMap<DeviceOs> userPlatforms;
|
||||
private final RamInfo ramInfo;
|
||||
private final BootstrapDumpInfo bootstrapInfo;
|
||||
@ -71,6 +77,27 @@ public class DumpInfo {
|
||||
|
||||
this.config = GeyserConnector.getInstance().getConfig();
|
||||
this.floodgateConfig = FloodgateConfigHolder.getConfig();
|
||||
|
||||
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();
|
||||
|
||||
this.userPlatforms = new Object2IntOpenHashMap<>();
|
||||
@ -108,6 +135,13 @@ public class DumpInfo {
|
||||
}
|
||||
}
|
||||
|
||||
@AllArgsConstructor
|
||||
@Getter
|
||||
public static class HashInfo {
|
||||
private final String md5Hash;
|
||||
private final String sha256Hash;
|
||||
}
|
||||
|
||||
@Getter
|
||||
public static class NetworkInfo {
|
||||
private final boolean dockerCheck;
|
||||
|
@ -34,4 +34,14 @@ public class AnimalEntity extends AgeableEntity {
|
||||
public AnimalEntity(long entityId, long geyserId, EntityType entityType, Vector3f position, Vector3f motion, Vector3f rotation) {
|
||||
super(entityId, geyserId, entityType, position, motion, rotation);
|
||||
}
|
||||
|
||||
/**
|
||||
* @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) {
|
||||
// This is what it defaults to. OK.
|
||||
return javaIdentifierStripped.equals("wheat");
|
||||
}
|
||||
}
|
||||
|
@ -26,6 +26,7 @@
|
||||
package org.geysermc.connector.entity.living.animal;
|
||||
|
||||
import com.github.steveice10.mc.protocol.data.game.entity.metadata.EntityMetadata;
|
||||
import com.google.common.collect.ImmutableSet;
|
||||
import com.nukkitx.math.vector.Vector3f;
|
||||
import com.nukkitx.protocol.bedrock.data.entity.EntityData;
|
||||
import com.nukkitx.protocol.bedrock.data.entity.EntityEventType;
|
||||
@ -34,7 +35,15 @@ import com.nukkitx.protocol.bedrock.packet.EntityEventPacket;
|
||||
import org.geysermc.connector.entity.type.EntityType;
|
||||
import org.geysermc.connector.network.session.GeyserSession;
|
||||
|
||||
import java.util.Set;
|
||||
|
||||
public class BeeEntity extends AnimalEntity {
|
||||
/**
|
||||
* A list of all flowers. Used for feeding bees.
|
||||
*/
|
||||
private static final Set<String> FLOWERS = ImmutableSet.of("dandelion", "poppy", "blue_orchid", "allium", "azure_bluet",
|
||||
"red_tulip", "pink_tulip", "white_tulip", "orange_tulip", "cornflower", "lily_of_the_valley", "wither_rose",
|
||||
"sunflower", "lilac", "rose_bush", "peony");
|
||||
|
||||
public BeeEntity(long entityId, long geyserId, EntityType entityType, Vector3f position, Vector3f motion, Vector3f rotation) {
|
||||
super(entityId, geyserId, entityType, position, motion, rotation);
|
||||
@ -63,4 +72,9 @@ public class BeeEntity extends AnimalEntity {
|
||||
}
|
||||
super.updateBedrockMetadata(entityMetadata, session);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean canEat(String javaIdentifierStripped) {
|
||||
return FLOWERS.contains(javaIdentifierStripped);
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,41 @@
|
||||
/*
|
||||
* 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.type.EntityType;
|
||||
|
||||
public class ChickenEntity extends AnimalEntity {
|
||||
|
||||
public ChickenEntity(long entityId, long geyserId, EntityType entityType, Vector3f position, Vector3f motion, Vector3f rotation) {
|
||||
super(entityId, geyserId, entityType, position, motion, rotation);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean canEat(String javaIdentifierStripped) {
|
||||
return javaIdentifierStripped.contains("seeds");
|
||||
}
|
||||
}
|
@ -52,4 +52,9 @@ public class FoxEntity extends AnimalEntity {
|
||||
}
|
||||
super.updateBedrockMetadata(entityMetadata, session);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean canEat(String javaIdentifierStripped) {
|
||||
return javaIdentifierStripped.equals("sweet_berries");
|
||||
}
|
||||
}
|
||||
|
@ -47,4 +47,9 @@ public class HoglinEntity extends AnimalEntity {
|
||||
}
|
||||
super.updateBedrockMetadata(entityMetadata, session);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean canEat(String javaIdentifierStripped) {
|
||||
return javaIdentifierStripped.equals("crimson_fungus");
|
||||
}
|
||||
}
|
||||
|
@ -44,4 +44,9 @@ public class OcelotEntity extends AnimalEntity {
|
||||
}
|
||||
super.updateBedrockMetadata(entityMetadata, session);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean canEat(String javaIdentifierStripped) {
|
||||
return javaIdentifierStripped.equals("cod") || javaIdentifierStripped.equals("salmon");
|
||||
}
|
||||
}
|
||||
|
@ -79,6 +79,11 @@ public class PandaEntity extends AnimalEntity {
|
||||
super.updateBedrockMetadata(entityMetadata, session);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean canEat(String javaIdentifierStripped) {
|
||||
return javaIdentifierStripped.equals("bamboo");
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the panda's appearance, and take into consideration the recessive brown and weak traits that only show up
|
||||
* when both main and hidden genes match
|
||||
|
@ -46,6 +46,11 @@ public class PigEntity extends AnimalEntity {
|
||||
super.updateBedrockMetadata(entityMetadata, session);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean canEat(String javaIdentifierStripped) {
|
||||
return javaIdentifierStripped.equals("carrot") || javaIdentifierStripped.equals("potato") || javaIdentifierStripped.equals("beetroot");
|
||||
}
|
||||
|
||||
@Override
|
||||
protected float getDefaultMaxHealth() {
|
||||
return 10f;
|
||||
|
@ -44,4 +44,9 @@ public class PolarBearEntity extends AnimalEntity {
|
||||
}
|
||||
super.updateBedrockMetadata(entityMetadata, session);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean canEat(String javaIdentifierStripped) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
@ -59,4 +59,9 @@ public class RabbitEntity extends AnimalEntity {
|
||||
metadata.put(EntityData.VARIANT, variant);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean canEat(String javaIdentifierStripped) {
|
||||
return javaIdentifierStripped.equals("dandelion") || javaIdentifierStripped.equals("carrot") || javaIdentifierStripped.equals("golden_carrot");
|
||||
}
|
||||
}
|
@ -85,4 +85,9 @@ public class StriderEntity extends AnimalEntity {
|
||||
|
||||
super.updateBedrockMetadata(session);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean canEat(String javaIdentifierStripped) {
|
||||
return javaIdentifierStripped.equals("warped_fungus");
|
||||
}
|
||||
}
|
||||
|
@ -46,4 +46,9 @@ public class TurtleEntity extends AnimalEntity {
|
||||
}
|
||||
super.updateBedrockMetadata(entityMetadata, session);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean canEat(String javaIdentifierStripped) {
|
||||
return javaIdentifierStripped.equals("seagrass");
|
||||
}
|
||||
}
|
||||
|
@ -26,6 +26,7 @@
|
||||
package org.geysermc.connector.entity.living.animal.horse;
|
||||
|
||||
import com.github.steveice10.mc.protocol.data.game.entity.metadata.EntityMetadata;
|
||||
import com.google.common.collect.ImmutableSet;
|
||||
import com.nukkitx.math.vector.Vector3f;
|
||||
import com.nukkitx.protocol.bedrock.data.entity.EntityData;
|
||||
import com.nukkitx.protocol.bedrock.data.entity.EntityEventType;
|
||||
@ -38,7 +39,15 @@ import org.geysermc.connector.entity.type.EntityType;
|
||||
import org.geysermc.connector.network.session.GeyserSession;
|
||||
import org.geysermc.connector.network.translators.item.ItemRegistry;
|
||||
|
||||
import java.util.Set;
|
||||
|
||||
public class AbstractHorseEntity extends AnimalEntity {
|
||||
/**
|
||||
* A list of all foods a horse/donkey can eat on Java Edition.
|
||||
* Used to display interactive tag if needed.
|
||||
*/
|
||||
private static final Set<String> DONKEY_AND_HORSE_FOODS = ImmutableSet.of("golden_apple", "enchanted_golden_apple",
|
||||
"golden_carrot", "sugar", "apple", "wheat", "hay_block");
|
||||
|
||||
public AbstractHorseEntity(long entityId, long geyserId, EntityType entityType, Vector3f position, Vector3f motion, Vector3f rotation) {
|
||||
super(entityId, geyserId, entityType, position, motion, rotation);
|
||||
@ -101,4 +110,9 @@ public class AbstractHorseEntity extends AnimalEntity {
|
||||
updateBedrockAttributes(session);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean canEat(String javaIdentifierStripped) {
|
||||
return DONKEY_AND_HORSE_FOODS.contains(javaIdentifierStripped);
|
||||
}
|
||||
}
|
||||
|
@ -75,4 +75,9 @@ public class LlamaEntity extends ChestedHorseEntity {
|
||||
}
|
||||
super.updateBedrockMetadata(entityMetadata, session);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean canEat(String javaIdentifierStripped) {
|
||||
return javaIdentifierStripped.equals("wheat") || javaIdentifierStripped.equals("hay_block");
|
||||
}
|
||||
}
|
||||
|
@ -83,4 +83,9 @@ public class CatEntity extends TameableEntity {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean canEat(String javaIdentifierStripped) {
|
||||
return javaIdentifierStripped.equals("cod") || javaIdentifierStripped.equals("salmon");
|
||||
}
|
||||
}
|
||||
|
@ -45,4 +45,9 @@ public class ParrotEntity extends TameableEntity {
|
||||
}
|
||||
super.updateBedrockMetadata(entityMetadata, session);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean canEat(String javaIdentifierStripped) {
|
||||
return javaIdentifierStripped.contains("seeds") || javaIdentifierStripped.equals("cookie");
|
||||
}
|
||||
}
|
||||
|
@ -26,13 +26,23 @@
|
||||
package org.geysermc.connector.entity.living.animal.tameable;
|
||||
|
||||
import com.github.steveice10.mc.protocol.data.game.entity.metadata.EntityMetadata;
|
||||
import com.google.common.collect.ImmutableSet;
|
||||
import com.nukkitx.math.vector.Vector3f;
|
||||
import com.nukkitx.protocol.bedrock.data.entity.EntityData;
|
||||
import com.nukkitx.protocol.bedrock.data.entity.EntityFlag;
|
||||
import org.geysermc.connector.entity.type.EntityType;
|
||||
import org.geysermc.connector.network.session.GeyserSession;
|
||||
|
||||
import java.util.Set;
|
||||
|
||||
public class WolfEntity extends TameableEntity {
|
||||
/**
|
||||
* A list of all foods a wolf can eat on Java Edition.
|
||||
* Used to display interactive tag or particles if needed.
|
||||
*/
|
||||
private static final Set<String> WOLF_FOODS = ImmutableSet.of("pufferfish", "tropical_fish", "chicken", "cooked_chicken",
|
||||
"porkchop", "beef", "rabbit", "cooked_porkchop", "cooked_beef", "rotten_flesh", "mutton", "cooked_mutton",
|
||||
"cooked_rabbit");
|
||||
|
||||
private byte collarColor;
|
||||
|
||||
@ -75,4 +85,10 @@ public class WolfEntity extends TameableEntity {
|
||||
|
||||
super.updateBedrockMetadata(entityMetadata, session);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean canEat(String javaIdentifierStripped) {
|
||||
// Cannot be a baby to eat these foods
|
||||
return WOLF_FOODS.contains(javaIdentifierStripped) && !metadata.getFlags().getFlag(EntityFlag.BABY);
|
||||
}
|
||||
}
|
||||
|
@ -42,7 +42,7 @@ public class AbstractSkeletonEntity extends MonsterEntity {
|
||||
if (entityMetadata.getId() == 14) {
|
||||
byte xd = (byte) entityMetadata.getValue();
|
||||
// A bit of a loophole so the hands get raised - set the target ID to its own ID
|
||||
metadata.put(EntityData.TARGET_EID, (xd == 4) ? geyserId : 0);
|
||||
metadata.put(EntityData.TARGET_EID, ((xd & 4) == 4) ? geyserId : 0);
|
||||
}
|
||||
super.updateBedrockMetadata(entityMetadata, session);
|
||||
}
|
||||
|
@ -25,13 +25,43 @@
|
||||
|
||||
package org.geysermc.connector.entity.living.monster.raid;
|
||||
|
||||
import com.github.steveice10.mc.protocol.data.game.entity.metadata.EntityMetadata;
|
||||
import com.nukkitx.math.vector.Vector3f;
|
||||
import org.geysermc.connector.entity.living.monster.raid.AbstractIllagerEntity;
|
||||
import com.nukkitx.protocol.bedrock.data.entity.EntityData;
|
||||
import com.nukkitx.protocol.bedrock.data.entity.EntityFlag;
|
||||
import org.geysermc.connector.entity.type.EntityType;
|
||||
import org.geysermc.connector.network.session.GeyserSession;
|
||||
|
||||
public class SpellcasterIllagerEntity extends AbstractIllagerEntity {
|
||||
private static final int SUMMON_VEX_PARTICLE_COLOR = (179 << 16) | (179 << 8) | 204;
|
||||
private static final int ATTACK_PARTICLE_COLOR = (102 << 16) | (77 << 8) | 89;
|
||||
private static final int WOLOLO_PARTICLE_COLOR = (179 << 16) | (128 << 8) | 51;
|
||||
|
||||
public SpellcasterIllagerEntity(long entityId, long geyserId, EntityType entityType, Vector3f position, Vector3f motion, Vector3f rotation) {
|
||||
super(entityId, geyserId, entityType, position, motion, rotation);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateBedrockMetadata(EntityMetadata entityMetadata, GeyserSession session) {
|
||||
if (entityMetadata.getId() == 16) {
|
||||
int spellType = (int) (byte) entityMetadata.getValue();
|
||||
// Summon vex, attack, or wololo
|
||||
metadata.getFlags().setFlag(EntityFlag.CASTING, spellType == 1 || spellType == 2 || spellType == 3);
|
||||
int rgbData = 0;
|
||||
// Set the spell color based on Java values
|
||||
switch (spellType) {
|
||||
case 1:
|
||||
rgbData = SUMMON_VEX_PARTICLE_COLOR;
|
||||
break;
|
||||
case 2:
|
||||
rgbData = ATTACK_PARTICLE_COLOR;
|
||||
break;
|
||||
case 3:
|
||||
rgbData = WOLOLO_PARTICLE_COLOR;
|
||||
break;
|
||||
}
|
||||
metadata.put(EntityData.EVOKER_SPELL_COLOR, rgbData);
|
||||
}
|
||||
super.updateBedrockMetadata(entityMetadata, session);
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,49 @@
|
||||
/*
|
||||
* 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.monster.raid;
|
||||
|
||||
import com.github.steveice10.mc.protocol.data.game.entity.metadata.EntityMetadata;
|
||||
import com.nukkitx.math.vector.Vector3f;
|
||||
import com.nukkitx.protocol.bedrock.data.entity.EntityFlag;
|
||||
import org.geysermc.connector.entity.type.EntityType;
|
||||
import org.geysermc.connector.network.session.GeyserSession;
|
||||
|
||||
public class VindicatorEntity extends AbstractIllagerEntity {
|
||||
|
||||
public VindicatorEntity(long entityId, long geyserId, EntityType entityType, Vector3f position, Vector3f motion, Vector3f rotation) {
|
||||
super(entityId, geyserId, entityType, position, motion, rotation);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateBedrockMetadata(EntityMetadata entityMetadata, GeyserSession session) {
|
||||
// Allow the axe to be shown if necessary
|
||||
if (entityMetadata.getId() == 14) {
|
||||
byte xd = (byte) entityMetadata.getValue();
|
||||
metadata.getFlags().setFlag(EntityFlag.ANGRY, (xd & 4) == 4);
|
||||
}
|
||||
super.updateBedrockMetadata(entityMetadata, session);
|
||||
}
|
||||
}
|
@ -36,10 +36,7 @@ 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.AbstractIllagerEntity;
|
||||
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.*;
|
||||
import org.geysermc.connector.entity.player.PlayerEntity;
|
||||
|
||||
import java.util.ArrayList;
|
||||
@ -48,7 +45,7 @@ import java.util.List;
|
||||
@Getter
|
||||
public enum EntityType {
|
||||
|
||||
CHICKEN(AnimalEntity.class, 10, 0.7f, 0.4f),
|
||||
CHICKEN(ChickenEntity.class, 10, 0.7f, 0.4f),
|
||||
COW(AnimalEntity.class, 11, 1.4f, 0.9f),
|
||||
PIG(PigEntity.class, 12, 0.9f),
|
||||
SHEEP(SheepEntity.class, 13, 1.3f, 0.9f),
|
||||
@ -97,7 +94,7 @@ public enum EntityType {
|
||||
SHULKER(ShulkerEntity.class, 54, 1f, 1f),
|
||||
ENDERMITE(MonsterEntity.class, 55, 0.3f, 0.4f),
|
||||
AGENT(Entity.class, 56, 0f),
|
||||
VINDICATOR(AbstractIllagerEntity.class, 57, 1.8f, 0.6f, 0.6f, 1.62f),
|
||||
VINDICATOR(VindicatorEntity.class, 57, 1.8f, 0.6f, 0.6f, 1.62f),
|
||||
PILLAGER(PillagerEntity.class, 114, 1.8f, 0.6f, 0.6f, 1.62f),
|
||||
WANDERING_TRADER(AbstractMerchantEntity.class, 118, 1.8f, 0.6f, 0.6f, 1.62f),
|
||||
PHANTOM(FlyingEntity.class, 58, 0.5f, 0.9f, 0.9f, 0.6f),
|
||||
@ -188,7 +185,7 @@ public enum EntityType {
|
||||
|
||||
static {
|
||||
List<String> allJavaIdentifiers = new ArrayList<>();
|
||||
for (EntityType type : values()) {
|
||||
for (EntityType type : VALUES) {
|
||||
if (type == AGENT || type == BALLOON || type == CHALKBOARD || type == NPC || type == TRIPOD_CAMERA || type == ENDER_DRAGON_PART) {
|
||||
continue;
|
||||
}
|
||||
|
@ -77,6 +77,7 @@ import lombok.Setter;
|
||||
import org.geysermc.connector.GeyserConnector;
|
||||
import org.geysermc.connector.command.CommandSender;
|
||||
import org.geysermc.connector.common.AuthType;
|
||||
import org.geysermc.connector.configuration.EmoteOffhandWorkaroundOption;
|
||||
import org.geysermc.connector.entity.Entity;
|
||||
import org.geysermc.connector.entity.Tickable;
|
||||
import org.geysermc.connector.entity.attribute.Attribute;
|
||||
@ -427,9 +428,7 @@ public class GeyserSession implements CommandSender {
|
||||
@Setter
|
||||
private boolean waitingForStatistics = false;
|
||||
|
||||
@Setter
|
||||
private List<UUID> selectedEmotes = new ArrayList<>();
|
||||
private final Set<UUID> emotes = new HashSet<>();
|
||||
private final Set<UUID> emotes;
|
||||
|
||||
/**
|
||||
* The thread that will run every 50 milliseconds - one Minecraft tick.
|
||||
@ -464,9 +463,14 @@ public class GeyserSession implements CommandSender {
|
||||
this.spawned = false;
|
||||
this.loggedIn = false;
|
||||
|
||||
// Make a copy to prevent ConcurrentModificationException
|
||||
final List<GeyserSession> tmpPlayers = new ArrayList<>(connector.getPlayers());
|
||||
tmpPlayers.forEach(player -> this.emotes.addAll(player.getEmotes()));
|
||||
if (connector.getConfig().getEmoteOffhandWorkaround() != EmoteOffhandWorkaroundOption.NO_EMOTES) {
|
||||
this.emotes = new HashSet<>();
|
||||
// Make a copy to prevent ConcurrentModificationException
|
||||
final List<GeyserSession> tmpPlayers = new ArrayList<>(connector.getPlayers());
|
||||
tmpPlayers.forEach(player -> this.emotes.addAll(player.getEmotes()));
|
||||
} else {
|
||||
this.emotes = null;
|
||||
}
|
||||
|
||||
bedrockServerSession.addDisconnectHandler(disconnectReason -> {
|
||||
InetAddress address = bedrockServerSession.getRealAddress().getAddress();
|
||||
@ -668,37 +672,50 @@ public class GeyserSession implements CommandSender {
|
||||
@Override
|
||||
public void packetSending(PacketSendingEvent event) {
|
||||
//todo move this somewhere else
|
||||
if (event.getPacket() instanceof HandshakePacket && floodgate) {
|
||||
byte[] encryptedData;
|
||||
if (event.getPacket() instanceof HandshakePacket) {
|
||||
String addressSuffix;
|
||||
if (floodgate) {
|
||||
byte[] encryptedData;
|
||||
|
||||
try {
|
||||
FloodgateSkinUploader skinUploader = connector.getSkinUploader();
|
||||
FloodgateCipher cipher = connector.getCipher();
|
||||
try {
|
||||
FloodgateSkinUploader skinUploader = connector.getSkinUploader();
|
||||
FloodgateCipher cipher = connector.getCipher();
|
||||
|
||||
encryptedData = cipher.encryptFromString(BedrockData.of(
|
||||
clientData.getGameVersion(),
|
||||
authData.getName(),
|
||||
authData.getXboxUUID(),
|
||||
clientData.getDeviceOs().ordinal(),
|
||||
clientData.getLanguageCode(),
|
||||
clientData.getUiProfile().ordinal(),
|
||||
clientData.getCurrentInputMode().ordinal(),
|
||||
upstream.getAddress().getAddress().getHostAddress(),
|
||||
skinUploader.getId(),
|
||||
skinUploader.getVerifyCode()
|
||||
).toString());
|
||||
} catch (Exception e) {
|
||||
connector.getLogger().error(LanguageUtils.getLocaleStringLog("geyser.auth.floodgate.encrypt_fail"), e);
|
||||
disconnect(LanguageUtils.getPlayerLocaleString("geyser.auth.floodgate.encryption_fail", getClientData().getLanguageCode()));
|
||||
return;
|
||||
encryptedData = cipher.encryptFromString(BedrockData.of(
|
||||
clientData.getGameVersion(),
|
||||
authData.getName(),
|
||||
authData.getXboxUUID(),
|
||||
clientData.getDeviceOs().ordinal(),
|
||||
clientData.getLanguageCode(),
|
||||
clientData.getUiProfile().ordinal(),
|
||||
clientData.getCurrentInputMode().ordinal(),
|
||||
upstream.getAddress().getAddress().getHostAddress(),
|
||||
skinUploader.getId(),
|
||||
skinUploader.getVerifyCode()
|
||||
).toString());
|
||||
} catch (Exception e) {
|
||||
connector.getLogger().error(LanguageUtils.getLocaleStringLog("geyser.auth.floodgate.encrypt_fail"), e);
|
||||
disconnect(LanguageUtils.getPlayerLocaleString("geyser.auth.floodgate.encryption_fail", getClientData().getLanguageCode()));
|
||||
return;
|
||||
}
|
||||
|
||||
addressSuffix = '\0' + new String(encryptedData, StandardCharsets.UTF_8);
|
||||
} else {
|
||||
addressSuffix = "";
|
||||
}
|
||||
|
||||
String finalDataString = new String(encryptedData, StandardCharsets.UTF_8);
|
||||
|
||||
HandshakePacket handshakePacket = event.getPacket();
|
||||
|
||||
String address;
|
||||
if (connector.getConfig().getRemote().isForwardHost()) {
|
||||
address = clientData.getServerAddress().split(":")[0];
|
||||
} else {
|
||||
address = handshakePacket.getHostname();
|
||||
}
|
||||
|
||||
event.setPacket(new HandshakePacket(
|
||||
handshakePacket.getProtocolVersion(),
|
||||
handshakePacket.getHostname() + '\0' + finalDataString,
|
||||
address + addressSuffix,
|
||||
handshakePacket.getPort(),
|
||||
handshakePacket.getIntent()
|
||||
));
|
||||
@ -825,7 +842,7 @@ public class GeyserSession implements CommandSender {
|
||||
/**
|
||||
* Called every 50 milliseconds - one Minecraft tick.
|
||||
*/
|
||||
public void tick() {
|
||||
protected void tick() {
|
||||
// Check to see if the player's position needs updating - a position update should be sent once every 3 seconds
|
||||
if (spawned && (System.currentTimeMillis() - lastMovementTimestamp) > 3000) {
|
||||
// Recalculate in case something else changed position
|
||||
@ -997,7 +1014,6 @@ public class GeyserSession implements CommandSender {
|
||||
startGamePacket.setLightningLevel(0);
|
||||
startGamePacket.setMultiplayerGame(true);
|
||||
startGamePacket.setBroadcastingToLan(true);
|
||||
startGamePacket.getGamerules().add(new GameRuleData<>("showcoordinates", connector.getConfig().isShowCoordinates()));
|
||||
startGamePacket.setPlatformBroadcastMode(GamePublishSetting.PUBLIC);
|
||||
startGamePacket.setXblBroadcastMode(GamePublishSetting.PUBLIC);
|
||||
startGamePacket.setCommandsEnabled(!connector.getConfig().isXboxAchievementsEnabled());
|
||||
@ -1189,13 +1205,14 @@ public class GeyserSession implements CommandSender {
|
||||
|
||||
/**
|
||||
* Update the cached value for the reduced debug info gamerule.
|
||||
* This also toggles the coordinates display
|
||||
* If enabled, also hides the player's coordinates.
|
||||
*
|
||||
* @param value The new value for reducedDebugInfo
|
||||
*/
|
||||
public void setReducedDebugInfo(boolean value) {
|
||||
worldCache.setShowCoordinates(!value);
|
||||
reducedDebugInfo = value;
|
||||
// Set the showCoordinates data. This is done because updateShowCoordinates() uses this gamerule as a variable.
|
||||
getWorldCache().updateShowCoordinates();
|
||||
}
|
||||
|
||||
/**
|
||||
@ -1281,7 +1298,6 @@ public class GeyserSession implements CommandSender {
|
||||
}
|
||||
|
||||
public void refreshEmotes(List<UUID> emotes) {
|
||||
this.selectedEmotes = emotes;
|
||||
this.emotes.addAll(emotes);
|
||||
for (GeyserSession player : connector.getPlayers()) {
|
||||
List<UUID> pieces = new ArrayList<>();
|
||||
|
@ -28,6 +28,7 @@ package org.geysermc.connector.network.session.cache;
|
||||
import com.github.steveice10.mc.protocol.data.game.setting.Difficulty;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
import org.geysermc.connector.configuration.GeyserConfiguration;
|
||||
import org.geysermc.connector.network.session.GeyserSession;
|
||||
import org.geysermc.connector.scoreboard.Objective;
|
||||
import org.geysermc.connector.scoreboard.Scoreboard;
|
||||
@ -38,7 +39,13 @@ public class WorldCache {
|
||||
private final GeyserSession session;
|
||||
@Setter
|
||||
private Difficulty difficulty = Difficulty.EASY;
|
||||
private boolean showCoordinates = true;
|
||||
|
||||
/**
|
||||
* True if the client prefers being shown their coordinates, regardless if they're being shown or not.
|
||||
* This will be true everytime the client joins the server because neither the client nor server store the preference permanently.
|
||||
*/
|
||||
@Setter
|
||||
private boolean prefersShowCoordinates = true;
|
||||
|
||||
private Scoreboard scoreboard;
|
||||
private final ScoreboardUpdater scoreboardUpdater;
|
||||
@ -66,12 +73,15 @@ public class WorldCache {
|
||||
}
|
||||
|
||||
/**
|
||||
* Tell the client to hide or show the coordinates
|
||||
* Tell the client to hide or show the coordinates.
|
||||
*
|
||||
* @param value True to show, false to hide
|
||||
* If {@link #prefersShowCoordinates} is true, coordinates will be shown, unless either of the following conditions apply: <br>
|
||||
* <br>
|
||||
* {@link GeyserSession#reducedDebugInfo} is enabled
|
||||
* {@link GeyserConfiguration#isShowCoordinates()} is disabled
|
||||
*/
|
||||
public void setShowCoordinates(boolean value) {
|
||||
showCoordinates = value;
|
||||
session.sendGameRule("showcoordinates", value);
|
||||
public void updateShowCoordinates() {
|
||||
boolean allowShowCoordinates = !session.isReducedDebugInfo() && session.getConnector().getConfig().isShowCoordinates();
|
||||
session.sendGameRule("showcoordinates", allowShowCoordinates && prefersShowCoordinates);
|
||||
}
|
||||
}
|
@ -26,6 +26,7 @@
|
||||
package org.geysermc.connector.network.translators.bedrock;
|
||||
|
||||
import com.nukkitx.protocol.bedrock.packet.EmoteListPacket;
|
||||
import org.geysermc.connector.configuration.EmoteOffhandWorkaroundOption;
|
||||
import org.geysermc.connector.network.session.GeyserSession;
|
||||
import org.geysermc.connector.network.translators.PacketTranslator;
|
||||
import org.geysermc.connector.network.translators.Translator;
|
||||
@ -35,6 +36,10 @@ public class BedrockEmoteListTranslator extends PacketTranslator<EmoteListPacket
|
||||
|
||||
@Override
|
||||
public void translate(EmoteListPacket packet, GeyserSession session) {
|
||||
if (session.getConnector().getConfig().getEmoteOffhandWorkaround() == EmoteOffhandWorkaroundOption.NO_EMOTES) {
|
||||
return;
|
||||
}
|
||||
|
||||
session.refreshEmotes(packet.getPieceIds());
|
||||
}
|
||||
}
|
||||
|
@ -321,7 +321,7 @@ public class BedrockInventoryTransactionTranslator extends PacketTranslator<Inve
|
||||
session.sendUpstreamPacket(openPacket);
|
||||
break;
|
||||
}
|
||||
Vector3f vector = packet.getClickPosition();
|
||||
Vector3f vector = packet.getClickPosition().sub(entity.getPosition());
|
||||
ClientPlayerInteractEntityPacket interactPacket = new ClientPlayerInteractEntityPacket((int) entity.getEntityId(),
|
||||
InteractAction.INTERACT, Hand.MAIN_HAND, session.isSneaking());
|
||||
ClientPlayerInteractEntityPacket interactAtPacket = new ClientPlayerInteractEntityPacket((int) entity.getEntityId(),
|
||||
@ -329,7 +329,7 @@ public class BedrockInventoryTransactionTranslator extends PacketTranslator<Inve
|
||||
session.sendDownstreamPacket(interactPacket);
|
||||
session.sendDownstreamPacket(interactAtPacket);
|
||||
|
||||
EntitySoundInteractionHandler.handleEntityInteraction(session, vector, entity);
|
||||
EntitySoundInteractionHandler.handleEntityInteraction(session, packet.getClickPosition(), entity);
|
||||
break;
|
||||
case 1: //Attack
|
||||
if (entity.getEntityType() == EntityType.ENDER_DRAGON) {
|
||||
|
@ -54,7 +54,7 @@ public class BedrockLecternUpdateTranslator extends PacketTranslator<LecternUpda
|
||||
// Emulate an interact packet
|
||||
ClientPlayerPlaceBlockPacket blockPacket = new ClientPlayerPlaceBlockPacket(
|
||||
new Position(packet.getBlockPosition().getX(), packet.getBlockPosition().getY(), packet.getBlockPosition().getZ()),
|
||||
BlockFace.values()[0],
|
||||
BlockFace.DOWN,
|
||||
Hand.MAIN_HAND,
|
||||
0, 0, 0, // Java doesn't care about these when dealing with a lectern
|
||||
false);
|
||||
|
@ -25,25 +25,43 @@
|
||||
|
||||
package org.geysermc.connector.network.translators.bedrock.entity.player;
|
||||
|
||||
import com.github.steveice10.mc.protocol.data.game.entity.player.PlayerAction;
|
||||
import com.github.steveice10.mc.protocol.data.game.world.block.BlockFace;
|
||||
import com.github.steveice10.mc.protocol.packet.ingame.client.player.ClientPlayerActionPacket;
|
||||
import com.nukkitx.protocol.bedrock.packet.EmotePacket;
|
||||
import org.geysermc.connector.configuration.EmoteOffhandWorkaroundOption;
|
||||
import org.geysermc.connector.entity.Entity;
|
||||
import org.geysermc.connector.network.session.GeyserSession;
|
||||
import org.geysermc.connector.network.translators.PacketTranslator;
|
||||
import org.geysermc.connector.network.translators.Translator;
|
||||
import org.geysermc.connector.utils.BlockUtils;
|
||||
|
||||
@Translator(packet = EmotePacket.class)
|
||||
public class BedrockEmoteTranslator extends PacketTranslator<EmotePacket> {
|
||||
|
||||
@Override
|
||||
public void translate(EmotePacket packet, GeyserSession session) {
|
||||
if (session.getConnector().getConfig().getEmoteOffhandWorkaround() != EmoteOffhandWorkaroundOption.DISABLED) {
|
||||
// Activate the workaround - we should trigger the offhand now
|
||||
ClientPlayerActionPacket swapHandsPacket = new ClientPlayerActionPacket(PlayerAction.SWAP_HANDS, BlockUtils.POSITION_ZERO,
|
||||
BlockFace.DOWN);
|
||||
session.sendDownstreamPacket(swapHandsPacket);
|
||||
|
||||
if (session.getConnector().getConfig().getEmoteOffhandWorkaround() == EmoteOffhandWorkaroundOption.NO_EMOTES) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
long javaId = session.getPlayerEntity().getEntityId();
|
||||
for (GeyserSession otherSession : session.getConnector().getPlayers()) {
|
||||
if (otherSession != session) {
|
||||
if (otherSession.isClosed()) continue;
|
||||
Entity otherEntity = otherSession.getEntityCache().getEntityByJavaId(javaId);
|
||||
if (otherEntity == null) continue;
|
||||
packet.setRuntimeEntityId(otherEntity.getGeyserId());
|
||||
otherSession.sendUpstreamPacket(packet);
|
||||
EmotePacket otherEmotePacket = new EmotePacket();
|
||||
otherEmotePacket.setEmoteId(packet.getEmoteId());
|
||||
otherEmotePacket.setRuntimeEntityId(otherEntity.getGeyserId());
|
||||
otherSession.sendUpstreamPacket(otherEmotePacket);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -72,7 +72,7 @@ public class EnchantingInventoryTranslator extends AbstractBlockInventoryTransla
|
||||
// The Bedrock index might need changed, so let's look it up and see.
|
||||
int bedrockIndex = value;
|
||||
if (bedrockIndex != -1) {
|
||||
Enchantment enchantment = Enchantment.getByJavaIdentifier("minecraft:" + JavaEnchantment.values()[bedrockIndex].name().toLowerCase());
|
||||
Enchantment enchantment = Enchantment.getByJavaIdentifier("minecraft:" + Enchantment.JavaEnchantment.of(bedrockIndex).name().toLowerCase());
|
||||
if (enchantment != null) {
|
||||
// Convert the Java enchantment index to Bedrock's
|
||||
bedrockIndex = enchantment.ordinal();
|
||||
@ -170,48 +170,4 @@ public class EnchantingInventoryTranslator extends AbstractBlockInventoryTransla
|
||||
public Inventory createInventory(String name, int windowId, WindowType windowType, PlayerInventory playerInventory) {
|
||||
return new EnchantingContainer(name, windowId, this.size, windowType, playerInventory);
|
||||
}
|
||||
|
||||
/**
|
||||
* Enchantments classified by their Java index
|
||||
*/
|
||||
public enum JavaEnchantment {
|
||||
PROTECTION,
|
||||
FIRE_PROTECTION,
|
||||
FEATHER_FALLING,
|
||||
BLAST_PROTECTION,
|
||||
PROJECTILE_PROTECTION,
|
||||
RESPIRATION,
|
||||
AQUA_AFFINITY,
|
||||
THORNS,
|
||||
DEPTH_STRIDER,
|
||||
FROST_WALKER,
|
||||
BINDING_CURSE,
|
||||
SOUL_SPEED,
|
||||
SHARPNESS,
|
||||
SMITE,
|
||||
BANE_OF_ARTHROPODS,
|
||||
KNOCKBACK,
|
||||
FIRE_ASPECT,
|
||||
LOOTING,
|
||||
SWEEPING,
|
||||
EFFICIENCY,
|
||||
SILK_TOUCH,
|
||||
UNBREAKING,
|
||||
FORTUNE,
|
||||
POWER,
|
||||
PUNCH,
|
||||
FLAME,
|
||||
INFINITY,
|
||||
LUCK_OF_THE_SEA,
|
||||
LURE,
|
||||
LOYALTY,
|
||||
IMPALING,
|
||||
RIPTIDE,
|
||||
CHANNELING,
|
||||
MULTISHOT,
|
||||
QUICK_CHARGE,
|
||||
PIERCING,
|
||||
MENDING,
|
||||
VANISHING_CURSE
|
||||
}
|
||||
}
|
||||
|
@ -69,17 +69,7 @@ public enum Enchantment {
|
||||
QUICK_CHARGE,
|
||||
SOUL_SPEED;
|
||||
|
||||
/**
|
||||
* A list of all enchantment Java identifiers for use with command suggestions.
|
||||
*/
|
||||
public static final String[] ALL_JAVA_IDENTIFIERS;
|
||||
|
||||
static {
|
||||
ALL_JAVA_IDENTIFIERS = new String[values().length];
|
||||
for (int i = 0; i < ALL_JAVA_IDENTIFIERS.length; i++) {
|
||||
ALL_JAVA_IDENTIFIERS[i] = values()[i].javaIdentifier;
|
||||
}
|
||||
}
|
||||
private static final Enchantment[] VALUES = values();
|
||||
|
||||
private final String javaIdentifier;
|
||||
|
||||
@ -88,7 +78,7 @@ public enum Enchantment {
|
||||
}
|
||||
|
||||
public static Enchantment getByJavaIdentifier(String javaIdentifier) {
|
||||
for (Enchantment enchantment : Enchantment.values()) {
|
||||
for (Enchantment enchantment : VALUES) {
|
||||
if (enchantment.javaIdentifier.equals(javaIdentifier) || enchantment.name().toLowerCase(Locale.ENGLISH).equalsIgnoreCase(javaIdentifier)) {
|
||||
return enchantment;
|
||||
}
|
||||
@ -97,9 +87,71 @@ public enum Enchantment {
|
||||
}
|
||||
|
||||
public static Enchantment getByBedrockId(int bedrockId) {
|
||||
if (bedrockId >= 0 && bedrockId < Enchantment.values().length) {
|
||||
return Enchantment.values()[bedrockId];
|
||||
if (bedrockId >= 0 && bedrockId < VALUES.length) {
|
||||
return VALUES[bedrockId];
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Enchantments classified by their Java index
|
||||
*/
|
||||
public enum JavaEnchantment {
|
||||
PROTECTION,
|
||||
FIRE_PROTECTION,
|
||||
FEATHER_FALLING,
|
||||
BLAST_PROTECTION,
|
||||
PROJECTILE_PROTECTION,
|
||||
RESPIRATION,
|
||||
AQUA_AFFINITY,
|
||||
THORNS,
|
||||
DEPTH_STRIDER,
|
||||
FROST_WALKER,
|
||||
BINDING_CURSE,
|
||||
SOUL_SPEED,
|
||||
SHARPNESS,
|
||||
SMITE,
|
||||
BANE_OF_ARTHROPODS,
|
||||
KNOCKBACK,
|
||||
FIRE_ASPECT,
|
||||
LOOTING,
|
||||
SWEEPING,
|
||||
EFFICIENCY,
|
||||
SILK_TOUCH,
|
||||
UNBREAKING,
|
||||
FORTUNE,
|
||||
POWER,
|
||||
PUNCH,
|
||||
FLAME,
|
||||
INFINITY,
|
||||
LUCK_OF_THE_SEA,
|
||||
LURE,
|
||||
LOYALTY,
|
||||
IMPALING,
|
||||
RIPTIDE,
|
||||
CHANNELING,
|
||||
MULTISHOT,
|
||||
QUICK_CHARGE,
|
||||
PIERCING,
|
||||
MENDING,
|
||||
VANISHING_CURSE;
|
||||
|
||||
private static final JavaEnchantment[] VALUES = JavaEnchantment.values();
|
||||
|
||||
public static JavaEnchantment of(int index) {
|
||||
return VALUES[index];
|
||||
}
|
||||
|
||||
/**
|
||||
* A list of all enchantment Java identifiers for use with command suggestions.
|
||||
*/
|
||||
public static final String[] ALL_JAVA_IDENTIFIERS;
|
||||
|
||||
static {
|
||||
ALL_JAVA_IDENTIFIERS = new String[VALUES.length];
|
||||
for (int i = 0; i < ALL_JAVA_IDENTIFIERS.length; i++) {
|
||||
ALL_JAVA_IDENTIFIERS[i] = "minecraft:" + VALUES[i].name().toLowerCase(Locale.ENGLISH);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -408,6 +408,13 @@ public class ItemRegistry {
|
||||
"", bedrockBlockId,
|
||||
stackSize);
|
||||
}
|
||||
} else if (entry.getKey().equals("minecraft:spectral_arrow") || entry.getKey().equals("minecraft:knowledge_book")) {
|
||||
// These items don't exist on Java, so set up a container that indicates they should have custom names
|
||||
itemEntry = new TranslatableItemEntry(
|
||||
entry.getKey(), bedrockIdentifier, itemIndex, bedrockId,
|
||||
entry.getValue().get("bedrock_data").intValue(),
|
||||
bedrockBlockId,
|
||||
stackSize);
|
||||
} else {
|
||||
itemEntry = new ItemEntry(
|
||||
entry.getKey(), bedrockIdentifier, itemIndex, bedrockId,
|
||||
@ -471,7 +478,6 @@ public class ItemRegistry {
|
||||
}
|
||||
|
||||
itemNames.add("minecraft:furnace_minecart");
|
||||
itemNames.add("minecraft:spectral_arrow");
|
||||
|
||||
if (lodestoneCompassId == 0) {
|
||||
throw new RuntimeException("Lodestone compass not found in item palette!");
|
||||
|
@ -40,6 +40,7 @@ import org.geysermc.connector.network.translators.ItemRemapper;
|
||||
import org.geysermc.connector.network.translators.chat.MessageTranslator;
|
||||
import org.geysermc.connector.utils.FileUtils;
|
||||
import org.geysermc.connector.utils.LanguageUtils;
|
||||
import org.geysermc.connector.utils.LocaleUtils;
|
||||
import org.reflections.Reflections;
|
||||
|
||||
import java.util.*;
|
||||
@ -137,8 +138,6 @@ public abstract class ItemTranslator {
|
||||
nbt.put(new IntTag("map", 0));
|
||||
}
|
||||
|
||||
ItemStack itemStack = new ItemStack(stack.getId(), stack.getAmount(), nbt);
|
||||
|
||||
if (nbt != null) {
|
||||
for (NbtItemStackTranslator translator : NBT_TRANSLATORS) {
|
||||
if (translator.acceptItem(bedrockItem)) {
|
||||
@ -147,7 +146,9 @@ public abstract class ItemTranslator {
|
||||
}
|
||||
}
|
||||
|
||||
translateDisplayProperties(session, nbt);
|
||||
nbt = translateDisplayProperties(session, nbt, bedrockItem);
|
||||
|
||||
ItemStack itemStack = new ItemStack(stack.getId(), stack.getAmount(), nbt);
|
||||
|
||||
ItemData.Builder builder;
|
||||
ItemTranslator itemStackTranslator = ITEM_STACK_TRANSLATORS.get(bedrockItem.getJavaId());
|
||||
@ -393,8 +394,20 @@ public abstract class ItemTranslator {
|
||||
* Translates the display name of the item
|
||||
* @param session the Bedrock client's session
|
||||
* @param tag the tag to translate
|
||||
* @param itemEntry the item entry, in case it requires translation
|
||||
*
|
||||
* @return the new tag to use, should the current one be null
|
||||
*/
|
||||
public static void translateDisplayProperties(GeyserSession session, CompoundTag tag) {
|
||||
public static CompoundTag translateDisplayProperties(GeyserSession session, CompoundTag tag, ItemEntry itemEntry) {
|
||||
return translateDisplayProperties(session, tag, itemEntry, 'f');
|
||||
}
|
||||
|
||||
/**
|
||||
* @param translationColor if this item is not available on Java, the color that the new name should be.
|
||||
* Normally, this should just be white, but for shulker boxes this should be gray.
|
||||
*/
|
||||
public static CompoundTag translateDisplayProperties(GeyserSession session, CompoundTag tag, ItemEntry itemEntry, char translationColor) {
|
||||
boolean hasCustomName = false;
|
||||
if (tag != null) {
|
||||
CompoundTag display = tag.get("display");
|
||||
if (display != null && display.contains("Name")) {
|
||||
@ -405,11 +418,32 @@ public abstract class ItemTranslator {
|
||||
|
||||
// Add the new name tag
|
||||
display.put(new StringTag("Name", name));
|
||||
// Indicate that a custom name is present
|
||||
hasCustomName = true;
|
||||
|
||||
// Add to the new root tag
|
||||
tag.put(display);
|
||||
}
|
||||
}
|
||||
|
||||
if (!hasCustomName && itemEntry instanceof TranslatableItemEntry) {
|
||||
// No custom name, but we need to localize the item's name
|
||||
if (tag == null) {
|
||||
tag = new CompoundTag("");
|
||||
}
|
||||
CompoundTag display = tag.get("display");
|
||||
if (display == null) {
|
||||
display = new CompoundTag("display");
|
||||
// Add to the new root tag
|
||||
tag.put(display);
|
||||
}
|
||||
|
||||
String translationKey = ((TranslatableItemEntry) itemEntry).getTranslationString();
|
||||
// Reset formatting since Bedrock defaults to italics
|
||||
display.put(new StringTag("Name", "§r§" + translationColor + LocaleUtils.getLocaleString(translationKey, session.getLocale())));
|
||||
}
|
||||
|
||||
return tag;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -74,6 +74,8 @@ public enum Potion {
|
||||
SLOW_FALLING(40),
|
||||
LONG_SLOW_FALLING(41);
|
||||
|
||||
public static final Potion[] VALUES = values();
|
||||
|
||||
private final String javaIdentifier;
|
||||
private final short bedrockId;
|
||||
|
||||
@ -83,7 +85,7 @@ public enum Potion {
|
||||
}
|
||||
|
||||
public static Potion getByJavaIdentifier(String javaIdentifier) {
|
||||
for (Potion potion : Potion.values()) {
|
||||
for (Potion potion : VALUES) {
|
||||
if (potion.javaIdentifier.equals(javaIdentifier)) {
|
||||
return potion;
|
||||
}
|
||||
@ -92,7 +94,7 @@ public enum Potion {
|
||||
}
|
||||
|
||||
public static Potion getByBedrockId(int bedrockId) {
|
||||
for (Potion potion : Potion.values()) {
|
||||
for (Potion potion : VALUES) {
|
||||
if (potion.bedrockId == bedrockId) {
|
||||
return potion;
|
||||
}
|
||||
|
@ -80,7 +80,7 @@ public class PotionMixRegistry {
|
||||
// Add all types of potions as inputs
|
||||
ItemEntry fillerIngredient = ingredients.get(0);
|
||||
for (ItemEntry input : inputs) {
|
||||
for (Potion potion : Potion.values()) {
|
||||
for (Potion potion : Potion.VALUES) {
|
||||
potionMixes.add(new PotionMixData(
|
||||
input.getBedrockId(), potion.getBedrockId(),
|
||||
fillerIngredient.getBedrockId(), fillerIngredient.getBedrockData(),
|
||||
|
@ -77,6 +77,8 @@ public enum TippedArrowPotion {
|
||||
SLOW_FALLING(41, ArrowParticleColors.SLOW_FALLING),
|
||||
LONG_SLOW_FALLING(42, ArrowParticleColors.SLOW_FALLING);
|
||||
|
||||
private static final TippedArrowPotion[] VALUES = values();
|
||||
|
||||
private final String javaIdentifier;
|
||||
private final short bedrockId;
|
||||
/**
|
||||
@ -92,7 +94,7 @@ public enum TippedArrowPotion {
|
||||
}
|
||||
|
||||
public static TippedArrowPotion getByJavaIdentifier(String javaIdentifier) {
|
||||
for (TippedArrowPotion potion : TippedArrowPotion.values()) {
|
||||
for (TippedArrowPotion potion : VALUES) {
|
||||
if (potion.javaIdentifier.equals(javaIdentifier)) {
|
||||
return potion;
|
||||
}
|
||||
@ -101,7 +103,7 @@ public enum TippedArrowPotion {
|
||||
}
|
||||
|
||||
public static TippedArrowPotion getByBedrockId(int bedrockId) {
|
||||
for (TippedArrowPotion potion : TippedArrowPotion.values()) {
|
||||
for (TippedArrowPotion potion : VALUES) {
|
||||
if (potion.bedrockId == bedrockId) {
|
||||
return potion;
|
||||
}
|
||||
@ -114,7 +116,7 @@ public enum TippedArrowPotion {
|
||||
* @return the tipped arrow potion that most closely resembles that color.
|
||||
*/
|
||||
public static TippedArrowPotion getByJavaColor(int color) {
|
||||
for (TippedArrowPotion potion : TippedArrowPotion.values()) {
|
||||
for (TippedArrowPotion potion : VALUES) {
|
||||
if (potion.javaColor == color) {
|
||||
return potion;
|
||||
}
|
||||
|
@ -0,0 +1,41 @@
|
||||
/*
|
||||
* 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.network.translators.item;
|
||||
|
||||
import lombok.Getter;
|
||||
|
||||
/**
|
||||
* Used when an item should have a custom name applied, if there already isn't one.
|
||||
*/
|
||||
public class TranslatableItemEntry extends ItemEntry {
|
||||
@Getter
|
||||
private final String translationString;
|
||||
|
||||
public TranslatableItemEntry(String javaIdentifier, String bedrockIdentifier, int javaId, int bedrockId, int bedrockData, int bedrockBlockId, int stackSize) {
|
||||
super(javaIdentifier, bedrockIdentifier, javaId, bedrockId, bedrockData, bedrockBlockId, stackSize);
|
||||
this.translationString = "item." + javaIdentifier.replace(":", ".");
|
||||
}
|
||||
}
|
@ -28,10 +28,7 @@ package org.geysermc.connector.network.translators.item.translators.nbt;
|
||||
import com.github.steveice10.opennbt.tag.builtin.*;
|
||||
import org.geysermc.connector.network.session.GeyserSession;
|
||||
import org.geysermc.connector.network.translators.ItemRemapper;
|
||||
import org.geysermc.connector.network.translators.item.ItemEntry;
|
||||
import org.geysermc.connector.network.translators.item.ItemRegistry;
|
||||
import org.geysermc.connector.network.translators.item.ItemTranslator;
|
||||
import org.geysermc.connector.network.translators.item.NbtItemStackTranslator;
|
||||
import org.geysermc.connector.network.translators.item.*;
|
||||
|
||||
@ItemRemapper
|
||||
public class ShulkerBoxItemTranslator extends NbtItemStackTranslator {
|
||||
@ -54,11 +51,13 @@ public class ShulkerBoxItemTranslator extends NbtItemStackTranslator {
|
||||
boxItemTag.put(new StringTag("Name", boxItemEntry.getBedrockIdentifier()));
|
||||
boxItemTag.put(new ShortTag("Damage", (short) boxItemEntry.getBedrockData()));
|
||||
boxItemTag.put(new ByteTag("Count", ((ByteTag) itemData.get("Count")).getValue()));
|
||||
if (itemData.contains("tag")) {
|
||||
// Only the display name is what we have interest in, so just translate that if relevant
|
||||
CompoundTag displayTag = itemData.get("tag");
|
||||
ItemTranslator.translateDisplayProperties(session, displayTag);
|
||||
boxItemTag.put(displayTag);
|
||||
// Only the display name is what we have interest in, so just translate that if relevant
|
||||
CompoundTag displayTag = itemData.get("tag");
|
||||
if (displayTag == null && boxItemEntry instanceof TranslatableItemEntry) {
|
||||
displayTag = new CompoundTag("tag");
|
||||
}
|
||||
if (displayTag != null) {
|
||||
boxItemTag.put(ItemTranslator.translateDisplayProperties(session, displayTag, boxItemEntry, '7'));
|
||||
}
|
||||
|
||||
itemsList.add(boxItemTag);
|
||||
|
@ -249,7 +249,7 @@ public class JavaDeclareCommandsTranslator extends PacketTranslator<ServerDeclar
|
||||
return ItemRegistry.ITEM_NAMES;
|
||||
|
||||
case ITEM_ENCHANTMENT:
|
||||
return Enchantment.ALL_JAVA_IDENTIFIERS; //TODO: inventory branch use Java enums
|
||||
return Enchantment.JavaEnchantment.ALL_JAVA_IDENTIFIERS;
|
||||
|
||||
case ENTITY_SUMMON:
|
||||
return EntityType.ALL_JAVA_IDENTIFIERS;
|
||||
|
@ -47,6 +47,8 @@ import java.util.List;
|
||||
|
||||
@Translator(packet = ServerJoinGamePacket.class)
|
||||
public class JavaJoinGameTranslator extends PacketTranslator<ServerJoinGamePacket> {
|
||||
private static final List<SkinPart> SKIN_PART_VALUES = Arrays.asList(SkinPart.values());
|
||||
|
||||
@Override
|
||||
public void translate(ServerJoinGamePacket packet, GeyserSession session) {
|
||||
PlayerEntity entity = session.getPlayerEntity();
|
||||
@ -86,12 +88,13 @@ public class JavaJoinGameTranslator extends PacketTranslator<ServerJoinGamePacke
|
||||
gamerulePacket.getGameRules().add(new GameRuleData<>("doimmediaterespawn", !packet.isEnableRespawnScreen()));
|
||||
session.sendUpstreamPacket(gamerulePacket);
|
||||
|
||||
session.setReducedDebugInfo(packet.isReducedDebugInfo());
|
||||
|
||||
session.setRenderDistance(packet.getViewDistance());
|
||||
|
||||
// We need to send our skin parts to the server otherwise java sees us with no hat, jacket etc
|
||||
String locale = session.getLocale();
|
||||
List<SkinPart> skinParts = Arrays.asList(SkinPart.values());
|
||||
ClientSettingsPacket clientSettingsPacket = new ClientSettingsPacket(locale, (byte) session.getRenderDistance(), ChatVisibility.FULL, true, skinParts, HandPreference.RIGHT_HAND);
|
||||
ClientSettingsPacket clientSettingsPacket = new ClientSettingsPacket(locale, (byte) session.getRenderDistance(), ChatVisibility.FULL, true, SKIN_PART_VALUES, HandPreference.RIGHT_HAND);
|
||||
session.sendDownstreamPacket(clientSettingsPacket);
|
||||
|
||||
session.sendDownstreamPacket(new ClientPluginMessagePacket("minecraft:brand", PluginMessageUtils.getGeyserBrandData()));
|
||||
|
@ -30,12 +30,14 @@ import com.nukkitx.protocol.bedrock.data.SoundEvent;
|
||||
import com.nukkitx.protocol.bedrock.data.LevelEventType;
|
||||
import com.nukkitx.protocol.bedrock.data.entity.EntityData;
|
||||
import com.nukkitx.protocol.bedrock.data.entity.EntityEventType;
|
||||
import com.nukkitx.protocol.bedrock.data.inventory.ItemData;
|
||||
import com.nukkitx.protocol.bedrock.packet.EntityEventPacket;
|
||||
import com.nukkitx.protocol.bedrock.packet.LevelEventPacket;
|
||||
import com.nukkitx.protocol.bedrock.packet.LevelSoundEvent2Packet;
|
||||
import com.nukkitx.protocol.bedrock.packet.SetEntityDataPacket;
|
||||
import com.nukkitx.protocol.bedrock.packet.SetEntityMotionPacket;
|
||||
import org.geysermc.connector.entity.Entity;
|
||||
import org.geysermc.connector.entity.LivingEntity;
|
||||
import org.geysermc.connector.entity.type.EntityType;
|
||||
import org.geysermc.connector.network.session.GeyserSession;
|
||||
import org.geysermc.connector.network.translators.PacketTranslator;
|
||||
@ -47,9 +49,11 @@ public class JavaEntityStatusTranslator extends PacketTranslator<ServerEntitySta
|
||||
|
||||
@Override
|
||||
public void translate(ServerEntityStatusPacket packet, GeyserSession session) {
|
||||
Entity entity = session.getEntityCache().getEntityByJavaId(packet.getEntityId());
|
||||
Entity entity;
|
||||
if (packet.getEntityId() == session.getPlayerEntity().getEntityId()) {
|
||||
entity = session.getPlayerEntity();
|
||||
} else {
|
||||
entity = session.getEntityCache().getEntityByJavaId(packet.getEntityId());
|
||||
}
|
||||
if (entity == null)
|
||||
return;
|
||||
@ -196,6 +200,19 @@ public class JavaEntityStatusTranslator extends PacketTranslator<ServerEntitySta
|
||||
equipmentBreakPacket.setIdentifier("");
|
||||
session.sendUpstreamPacket(equipmentBreakPacket);
|
||||
return;
|
||||
case PLAYER_SWAP_SAME_ITEM: // Not just used for players
|
||||
if (entity instanceof LivingEntity) {
|
||||
LivingEntity livingEntity = (LivingEntity) entity;
|
||||
ItemData newMainHand = livingEntity.getOffHand();
|
||||
livingEntity.setOffHand(livingEntity.getHand());
|
||||
livingEntity.setHand(newMainHand);
|
||||
|
||||
livingEntity.updateMainHand(session);
|
||||
livingEntity.updateOffHand(session);
|
||||
} else {
|
||||
session.getConnector().getLogger().debug("Got status message to swap hands for a non-living entity.");
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
session.sendUpstreamPacket(entityEventPacket);
|
||||
|
@ -25,11 +25,9 @@
|
||||
|
||||
package org.geysermc.connector.network.translators.sound;
|
||||
|
||||
import com.github.steveice10.mc.protocol.data.game.entity.metadata.ItemStack;
|
||||
import com.nukkitx.math.vector.Vector3f;
|
||||
import org.geysermc.connector.inventory.GeyserItemStack;
|
||||
import org.geysermc.connector.network.session.GeyserSession;
|
||||
import org.geysermc.connector.network.translators.item.ItemRegistry;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
@ -47,6 +45,9 @@ public interface BlockSoundInteractionHandler extends SoundInteractionHandler<St
|
||||
* @param identifier the identifier of the block
|
||||
*/
|
||||
static void handleBlockInteraction(GeyserSession session, Vector3f position, String identifier) {
|
||||
// If we need to get the hand identifier, only get it once and save it to a variable
|
||||
String handIdentifier = null;
|
||||
|
||||
for (Map.Entry<SoundHandler, SoundInteractionHandler<?>> interactionEntry : SoundHandlerRegistry.INTERACTION_HANDLERS.entrySet()) {
|
||||
if (!(interactionEntry.getValue() instanceof BlockSoundInteractionHandler)) {
|
||||
continue;
|
||||
@ -66,7 +67,9 @@ public interface BlockSoundInteractionHandler extends SoundInteractionHandler<St
|
||||
if (itemInHand.isEmpty()) {
|
||||
continue;
|
||||
}
|
||||
String handIdentifier = itemInHand.getItemEntry().getJavaIdentifier();
|
||||
if (handIdentifier == null) {
|
||||
handIdentifier = itemInHand.getItemEntry().getJavaIdentifier();
|
||||
}
|
||||
boolean contains = false;
|
||||
for (String itemIdentifier : interactionEntry.getKey().items()) {
|
||||
if (handIdentifier.contains(itemIdentifier)) {
|
||||
|
@ -25,12 +25,10 @@
|
||||
|
||||
package org.geysermc.connector.network.translators.sound;
|
||||
|
||||
import com.github.steveice10.mc.protocol.data.game.entity.metadata.ItemStack;
|
||||
import com.nukkitx.math.vector.Vector3f;
|
||||
import org.geysermc.connector.entity.Entity;
|
||||
import org.geysermc.connector.inventory.GeyserItemStack;
|
||||
import org.geysermc.connector.network.session.GeyserSession;
|
||||
import org.geysermc.connector.network.translators.item.ItemRegistry;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
@ -48,6 +46,9 @@ public interface EntitySoundInteractionHandler extends SoundInteractionHandler<E
|
||||
* @param entity the entity interacted with
|
||||
*/
|
||||
static void handleEntityInteraction(GeyserSession session, Vector3f position, Entity entity) {
|
||||
// If we need to get the hand identifier, only get it once and save it to a variable
|
||||
String handIdentifier = null;
|
||||
|
||||
for (Map.Entry<SoundHandler, SoundInteractionHandler<?>> interactionEntry : SoundHandlerRegistry.INTERACTION_HANDLERS.entrySet()) {
|
||||
if (!(interactionEntry.getValue() instanceof EntitySoundInteractionHandler)) {
|
||||
continue;
|
||||
@ -67,7 +68,10 @@ public interface EntitySoundInteractionHandler extends SoundInteractionHandler<E
|
||||
if (itemInHand.isEmpty()) {
|
||||
continue;
|
||||
}
|
||||
String handIdentifier = itemInHand.getItemEntry().getJavaIdentifier();
|
||||
if (handIdentifier == null) {
|
||||
// Don't get the identifier unless we need it
|
||||
handIdentifier = itemInHand.getItemEntry().getJavaIdentifier();
|
||||
}
|
||||
boolean contains = false;
|
||||
for (String itemIdentifier : interactionEntry.getKey().items()) {
|
||||
if (handIdentifier.contains(itemIdentifier)) {
|
||||
|
@ -59,7 +59,7 @@ public @interface SoundHandler {
|
||||
* Leave empty to ignore.
|
||||
*
|
||||
* Only applies to interaction handlers that are an
|
||||
* instance of {@link BlockSoundInteractionHandler}.
|
||||
* instance of {@link EntitySoundInteractionHandler}.
|
||||
*
|
||||
* @return the value the item in the player's hand must contain
|
||||
*/
|
||||
|
@ -33,7 +33,7 @@ import org.geysermc.connector.network.translators.sound.BlockSoundInteractionHan
|
||||
import org.geysermc.connector.network.translators.sound.SoundHandler;
|
||||
|
||||
@SoundHandler(blocks = "comparator")
|
||||
public class ComparatorSoundInteractHandler implements BlockSoundInteractionHandler {
|
||||
public class ComparatorSoundInteractionHandler implements BlockSoundInteractionHandler {
|
||||
|
||||
@Override
|
||||
public void handleInteraction(GeyserSession session, Vector3f position, String identifier) {
|
@ -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.network.translators.sound.entity;
|
||||
|
||||
import com.nukkitx.math.vector.Vector3f;
|
||||
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.Entity;
|
||||
import org.geysermc.connector.entity.living.animal.AnimalEntity;
|
||||
import org.geysermc.connector.entity.living.animal.OcelotEntity;
|
||||
import org.geysermc.connector.entity.living.animal.tameable.CatEntity;
|
||||
import org.geysermc.connector.network.session.GeyserSession;
|
||||
import org.geysermc.connector.network.translators.sound.EntitySoundInteractionHandler;
|
||||
import org.geysermc.connector.network.translators.sound.SoundHandler;
|
||||
|
||||
@SoundHandler
|
||||
public class FeedBabySoundInteractionHandler implements EntitySoundInteractionHandler {
|
||||
|
||||
@Override
|
||||
public void handleInteraction(GeyserSession session, Vector3f position, Entity entity) {
|
||||
if (entity instanceof AnimalEntity && !(entity instanceof CatEntity || entity instanceof OcelotEntity)) {
|
||||
String handIdentifier = session.getPlayerInventory().getItemInHand().getItemEntry().getJavaIdentifier();
|
||||
boolean isBaby = entity.getMetadata().getFlags().getFlag(EntityFlag.BABY);
|
||||
if (isBaby && ((AnimalEntity) entity).canEat(handIdentifier.replace("minecraft:", ""))) {
|
||||
// Play the "feed child" effect
|
||||
EntityEventPacket feedEvent = new EntityEventPacket();
|
||||
feedEvent.setRuntimeEntityId(entity.getGeyserId());
|
||||
feedEvent.setType(EntityEventType.BABY_ANIMAL_FEED);
|
||||
session.sendUpstreamPacket(feedEvent);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -62,10 +62,6 @@ public class BlockStorage {
|
||||
return (version.getId() << 1) | (runtime ? 1 : 0);
|
||||
}
|
||||
|
||||
private static BitArrayVersion getVersionFromHeader(byte header) {
|
||||
return BitArrayVersion.get(header >> 1, true);
|
||||
}
|
||||
|
||||
public int getFullBlock(int index) {
|
||||
return this.palette.getInt(this.bitArray.get(index));
|
||||
}
|
||||
|
@ -25,12 +25,12 @@
|
||||
|
||||
package org.geysermc.connector.utils;
|
||||
|
||||
import com.google.common.collect.ImmutableSet;
|
||||
import com.nukkitx.protocol.bedrock.data.entity.EntityData;
|
||||
import com.nukkitx.protocol.bedrock.data.entity.EntityDataMap;
|
||||
import com.nukkitx.protocol.bedrock.data.entity.EntityFlag;
|
||||
import lombok.Getter;
|
||||
import org.geysermc.connector.entity.Entity;
|
||||
import org.geysermc.connector.entity.living.animal.AnimalEntity;
|
||||
import org.geysermc.connector.entity.living.animal.horse.HorseEntity;
|
||||
import org.geysermc.connector.entity.type.EntityType;
|
||||
import org.geysermc.connector.network.session.GeyserSession;
|
||||
@ -40,20 +40,6 @@ import java.util.EnumSet;
|
||||
import java.util.Set;
|
||||
|
||||
public class InteractiveTagManager {
|
||||
/**
|
||||
* A list of all foods a horse/donkey can eat on Java Edition.
|
||||
* Used to display interactive tag if needed.
|
||||
*/
|
||||
private static final Set<String> DONKEY_AND_HORSE_FOODS = ImmutableSet.of("golden_apple", "enchanted_golden_apple",
|
||||
"golden_carrot", "sugar", "apple", "wheat", "hay_block");
|
||||
|
||||
/**
|
||||
* A list of all flowers. Used for feeding bees.
|
||||
*/
|
||||
private static final Set<String> FLOWERS = ImmutableSet.of("dandelion", "poppy", "blue_orchid", "allium", "azure_bluet",
|
||||
"red_tulip", "pink_tulip", "white_tulip", "orange_tulip", "cornflower", "lily_of_the_valley", "wither_rose",
|
||||
"sunflower", "lilac", "rose_bush", "peony");
|
||||
|
||||
/**
|
||||
* All entity types that can be leashed on Java Edition
|
||||
*/
|
||||
@ -66,14 +52,6 @@ public class InteractiveTagManager {
|
||||
private static final Set<EntityType> SADDLEABLE_WHEN_TAMED_MOB_TYPES = EnumSet.of(EntityType.DONKEY, EntityType.HORSE,
|
||||
EntityType.ZOMBIE_HORSE, EntityType.MULE);
|
||||
|
||||
/**
|
||||
* A list of all foods a wolf can eat on Java Edition.
|
||||
* Used to display interactive tag if needed.
|
||||
*/
|
||||
private static final Set<String> WOLF_FOODS = ImmutableSet.of("pufferfish", "tropical_fish", "chicken", "cooked_chicken",
|
||||
"porkchop", "beef", "rabbit", "cooked_porkchop", "cooked_beef", "rotten_flesh", "mutton", "cooked_mutton",
|
||||
"cooked_rabbit");
|
||||
|
||||
/**
|
||||
* Update the suggestion that the client currently has on their screen for this entity (for example, "Feed" or "Ride")
|
||||
*
|
||||
@ -85,9 +63,8 @@ public class InteractiveTagManager {
|
||||
ItemEntry itemEntry = session.getPlayerInventory().getItemInHand().getItemEntry();
|
||||
String javaIdentifierStripped = itemEntry.getJavaIdentifier().replace("minecraft:", "");
|
||||
|
||||
// TODO - in the future, update these in the metadata? So the client doesn't have to wiggle their cursor around for it to happen
|
||||
// TODO - also, might be good to abstract out the eating thing. I know there will need to be food tracked for https://github.com/GeyserMC/Geyser/issues/1005 but not all food is breeding food
|
||||
InteractiveTag interactiveTag = InteractiveTag.NONE;
|
||||
|
||||
if (entityMetadata.getLong(EntityData.LEASH_HOLDER_EID) == session.getPlayerEntity().getGeyserId()) {
|
||||
// Unleash the entity
|
||||
interactiveTag = InteractiveTag.REMOVE_LEASH;
|
||||
@ -105,31 +82,24 @@ public class InteractiveTagManager {
|
||||
// Holding a leash and the mob is leashable for sure
|
||||
// (Plugins can change this behavior so that's something to look into in the far far future)
|
||||
interactiveTag = InteractiveTag.LEASH;
|
||||
} else if (interactEntity instanceof AnimalEntity && ((AnimalEntity) interactEntity).canEat(javaIdentifierStripped)) {
|
||||
// This animal can be fed
|
||||
interactiveTag = InteractiveTag.FEED;
|
||||
} else {
|
||||
switch (interactEntity.getEntityType()) {
|
||||
case BEE:
|
||||
if (FLOWERS.contains(javaIdentifierStripped)) {
|
||||
interactiveTag = InteractiveTag.FEED;
|
||||
case BOAT:
|
||||
if (interactEntity.getPassengers().size() < 2) {
|
||||
interactiveTag = InteractiveTag.BOARD_BOAT;
|
||||
}
|
||||
break;
|
||||
case BOAT:
|
||||
interactiveTag = InteractiveTag.BOARD_BOAT;
|
||||
break;
|
||||
case CAT:
|
||||
if (javaIdentifierStripped.equals("cod") || javaIdentifierStripped.equals("salmon")) {
|
||||
interactiveTag = InteractiveTag.FEED;
|
||||
} else if (entityMetadata.getFlags().getFlag(EntityFlag.TAMED) &&
|
||||
if (entityMetadata.getFlags().getFlag(EntityFlag.TAMED) &&
|
||||
entityMetadata.getLong(EntityData.OWNER_EID) == session.getPlayerEntity().getGeyserId()) {
|
||||
// Tamed and owned by player - can sit/stand
|
||||
interactiveTag = entityMetadata.getFlags().getFlag(EntityFlag.SITTING) ? InteractiveTag.STAND : InteractiveTag.SIT;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case CHICKEN:
|
||||
if (javaIdentifierStripped.contains("seeds")) {
|
||||
interactiveTag = InteractiveTag.FEED;
|
||||
}
|
||||
break;
|
||||
case MOOSHROOM:
|
||||
// Shear the mooshroom
|
||||
if (javaIdentifierStripped.equals("shears")) {
|
||||
@ -143,9 +113,7 @@ public class InteractiveTagManager {
|
||||
}
|
||||
// Fall down to COW as this works on mooshrooms
|
||||
case COW:
|
||||
if (javaIdentifierStripped.equals("wheat")) {
|
||||
interactiveTag = InteractiveTag.FEED;
|
||||
} else if (javaIdentifierStripped.equals("bucket")) {
|
||||
if (javaIdentifierStripped.equals("bucket")) {
|
||||
// Milk the cow
|
||||
interactiveTag = InteractiveTag.MILK;
|
||||
}
|
||||
@ -175,69 +143,28 @@ public class InteractiveTagManager {
|
||||
interactiveTag = InteractiveTag.OPEN_CONTAINER;
|
||||
break;
|
||||
}
|
||||
// have another switch statement as, while these share mount attributes they don't share food
|
||||
switch (interactEntity.getEntityType()) {
|
||||
case LLAMA:
|
||||
case TRADER_LLAMA:
|
||||
if (javaIdentifierStripped.equals("wheat") || javaIdentifierStripped.equals("hay_block")) {
|
||||
interactiveTag = InteractiveTag.FEED;
|
||||
break;
|
||||
}
|
||||
case DONKEY:
|
||||
case HORSE:
|
||||
// Undead can't eat
|
||||
if (DONKEY_AND_HORSE_FOODS.contains(javaIdentifierStripped)) {
|
||||
interactiveTag = InteractiveTag.FEED;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!entityMetadata.getFlags().getFlag(EntityFlag.BABY)) {
|
||||
// Can't ride a baby
|
||||
if (tamed) {
|
||||
interactiveTag = InteractiveTag.RIDE_HORSE;
|
||||
} else if (itemEntry.equals(ItemEntry.AIR)) {
|
||||
} else if (itemEntry.getJavaId() == 0) {
|
||||
// Can't hide an untamed entity without having your hand empty
|
||||
interactiveTag = InteractiveTag.MOUNT;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case FOX:
|
||||
if (javaIdentifierStripped.equals("sweet_berries")) {
|
||||
interactiveTag = InteractiveTag.FEED;
|
||||
}
|
||||
break;
|
||||
case HOGLIN:
|
||||
if (javaIdentifierStripped.equals("crimson_fungus")) {
|
||||
interactiveTag = InteractiveTag.FEED;
|
||||
}
|
||||
break;
|
||||
case MINECART:
|
||||
interactiveTag = InteractiveTag.RIDE_MINECART;
|
||||
if (interactEntity.getPassengers().isEmpty()) {
|
||||
interactiveTag = InteractiveTag.RIDE_MINECART;
|
||||
}
|
||||
break;
|
||||
case MINECART_CHEST:
|
||||
case MINECART_COMMAND_BLOCK:
|
||||
case MINECART_HOPPER:
|
||||
interactiveTag = InteractiveTag.OPEN_CONTAINER;
|
||||
break;
|
||||
case OCELOT:
|
||||
if (javaIdentifierStripped.equals("cod") || javaIdentifierStripped.equals("salmon")) {
|
||||
interactiveTag = InteractiveTag.FEED;
|
||||
}
|
||||
break;
|
||||
case PANDA:
|
||||
if (javaIdentifierStripped.equals("bamboo")) {
|
||||
interactiveTag = InteractiveTag.FEED;
|
||||
}
|
||||
break;
|
||||
case PARROT:
|
||||
if (javaIdentifierStripped.contains("seeds") || javaIdentifierStripped.equals("cookie")) {
|
||||
interactiveTag = InteractiveTag.FEED;
|
||||
}
|
||||
break;
|
||||
case PIG:
|
||||
if (javaIdentifierStripped.equals("carrot") || javaIdentifierStripped.equals("potato") || javaIdentifierStripped.equals("beetroot")) {
|
||||
interactiveTag = InteractiveTag.FEED;
|
||||
} else if (entityMetadata.getFlags().getFlag(EntityFlag.SADDLED)) {
|
||||
if (entityMetadata.getFlags().getFlag(EntityFlag.SADDLED)) {
|
||||
interactiveTag = InteractiveTag.MOUNT;
|
||||
}
|
||||
break;
|
||||
@ -246,15 +173,8 @@ public class InteractiveTagManager {
|
||||
interactiveTag = InteractiveTag.BARTER;
|
||||
}
|
||||
break;
|
||||
case RABBIT:
|
||||
if (javaIdentifierStripped.equals("dandelion") || javaIdentifierStripped.equals("carrot") || javaIdentifierStripped.equals("golden_carrot")) {
|
||||
interactiveTag = InteractiveTag.FEED;
|
||||
}
|
||||
break;
|
||||
case SHEEP:
|
||||
if (javaIdentifierStripped.equals("wheat")) {
|
||||
interactiveTag = InteractiveTag.FEED;
|
||||
} else if (!entityMetadata.getFlags().getFlag(EntityFlag.SHEARED)) {
|
||||
if (!entityMetadata.getFlags().getFlag(EntityFlag.SHEARED)) {
|
||||
if (javaIdentifierStripped.equals("shears")) {
|
||||
// Shear the sheep
|
||||
interactiveTag = InteractiveTag.SHEAR;
|
||||
@ -265,17 +185,10 @@ public class InteractiveTagManager {
|
||||
}
|
||||
break;
|
||||
case STRIDER:
|
||||
if (javaIdentifierStripped.equals("warped_fungus")) {
|
||||
interactiveTag = InteractiveTag.FEED;
|
||||
} else if (entityMetadata.getFlags().getFlag(EntityFlag.SADDLED)) {
|
||||
if (entityMetadata.getFlags().getFlag(EntityFlag.SADDLED)) {
|
||||
interactiveTag = InteractiveTag.RIDE_STRIDER;
|
||||
}
|
||||
break;
|
||||
case TURTLE:
|
||||
if (javaIdentifierStripped.equals("seagrass")) {
|
||||
interactiveTag = InteractiveTag.FEED;
|
||||
}
|
||||
break;
|
||||
case VILLAGER:
|
||||
if (entityMetadata.getInt(EntityData.VARIANT) != 14 && entityMetadata.getInt(EntityData.VARIANT) != 0
|
||||
&& entityMetadata.getFloat(EntityData.SCALE) >= 0.75f) { // Not a nitwit, has a profession and is not a baby
|
||||
@ -289,10 +202,6 @@ public class InteractiveTagManager {
|
||||
if (javaIdentifierStripped.equals("bone") && !entityMetadata.getFlags().getFlag(EntityFlag.TAMED)) {
|
||||
// Bone and untamed - can tame
|
||||
interactiveTag = InteractiveTag.TAME;
|
||||
} else if (WOLF_FOODS.contains(javaIdentifierStripped)) {
|
||||
// Compatible food in hand - feed
|
||||
// Sometimes just sits/stands when the wolf isn't hungry - there doesn't appear to be a way to fix this
|
||||
interactiveTag = InteractiveTag.FEED;
|
||||
} else if (entityMetadata.getFlags().getFlag(EntityFlag.TAMED) &&
|
||||
entityMetadata.getLong(EntityData.OWNER_EID) == session.getPlayerEntity().getGeyserId()) {
|
||||
// Tamed and owned by player - can sit/stand
|
||||
|
@ -35,7 +35,6 @@ import org.geysermc.cumulus.component.DropdownComponent;
|
||||
import org.geysermc.cumulus.response.CustomFormResponse;
|
||||
|
||||
public class SettingsUtils {
|
||||
|
||||
/**
|
||||
* Build a settings form for the given session and store it for later
|
||||
*
|
||||
@ -48,9 +47,13 @@ public class SettingsUtils {
|
||||
CustomForm.Builder builder = CustomForm.builder()
|
||||
.translator(LanguageUtils::getPlayerLocaleString, language)
|
||||
.title("geyser.settings.title.main")
|
||||
.iconPath("textures/ui/settings_glyph_color_2x.png")
|
||||
.label("geyser.settings.title.client")
|
||||
.toggle("geyser.settings.option.coordinates");
|
||||
.iconPath("textures/ui/settings_glyph_color_2x.png");
|
||||
|
||||
// Client can only see its coordinates if reducedDebugInfo is disabled and coordinates are enabled in geyser config.
|
||||
if (!session.isReducedDebugInfo() && session.getConnector().getConfig().isShowCoordinates()) {
|
||||
builder.label("geyser.settings.title.client")
|
||||
.toggle("geyser.settings.option.coordinates", session.getWorldCache().isPrefersShowCoordinates());
|
||||
}
|
||||
|
||||
|
||||
if (session.getOpPermissionLevel() >= 2 || session.hasPermission("geyser.settings.server")) {
|
||||
@ -94,7 +97,13 @@ public class SettingsUtils {
|
||||
return;
|
||||
}
|
||||
|
||||
session.getWorldCache().setShowCoordinates(response.next());
|
||||
// Client can only see its coordinates if reducedDebugInfo is disabled and coordinates are enabled in geyser config.
|
||||
if (!session.isReducedDebugInfo() && session.getConnector().getConfig().isShowCoordinates()) {
|
||||
response.skip(); // Client settings title
|
||||
|
||||
session.getWorldCache().setPrefersShowCoordinates(response.next());
|
||||
session.getWorldCache().updateShowCoordinates();
|
||||
}
|
||||
|
||||
if (session.getOpPermissionLevel() >= 2 || session.hasPermission("geyser.settings.server")) {
|
||||
GameMode gameMode = GameMode.values()[(int) response.next()];
|
||||
|
@ -53,6 +53,9 @@ remote:
|
||||
# 2) You run Velocity or BungeeCord with the option enabled in the proxy's main config.
|
||||
# IF YOU DON'T KNOW WHAT THIS IS, DON'T TOUCH IT!
|
||||
use-proxy-protocol: false
|
||||
# Forward the hostname that the Bedrock client used to connect over to the Java server
|
||||
# This is designed to be used for forced hosts on proxies
|
||||
forward-hostname: false
|
||||
|
||||
# Floodgate uses encryption to ensure use from authorised sources.
|
||||
# This should point to the public key generated by Floodgate (BungeeCord, Spigot or Velocity)
|
||||
@ -121,6 +124,13 @@ show-cooldown: title
|
||||
# Controls if coordinates are shown to players.
|
||||
show-coordinates: true
|
||||
|
||||
# If set, when a Bedrock player performs any emote, it will swap the offhand and mainhand items, just like the Java Edition keybind
|
||||
# There are three options this can be set to:
|
||||
# disabled - the default/fallback, which doesn't apply this workaround
|
||||
# no-emotes - emotes will NOT be sent to other Bedrock clients and offhand will be swapped. This effectively disables all emotes from being seen.
|
||||
# emotes-and-offhand - emotes will be sent to Bedrock clients and offhand will be swapped
|
||||
emote-offhand-workaround: "disabled"
|
||||
|
||||
# The default locale if we dont have the one the client requested. Uncomment to not use the default system language.
|
||||
# default-locale: en_us
|
||||
|
||||
|
Laden…
In neuem Issue referenzieren
Einen Benutzer sperren