mirror of
https://github.com/GeyserMC/Geyser.git
synced 2025-01-08 19:33:58 +01:00
Merge branch 'master' of https://github.com/GeyserMC/Geyser into feature/configurate
This commit is contained in:
commit
2034ffa49b
38 changed files with 13611 additions and 116 deletions
|
@ -15,7 +15,7 @@ The ultimate goal of this project is to allow Minecraft: Bedrock Edition users t
|
|||
Special thanks to the DragonProxy project for being a trailblazer in protocol translation and for all the team members who have joined us here!
|
||||
|
||||
## Supported Versions
|
||||
Geyser is currently supporting Minecraft Bedrock 1.20.80 - 1.21.21 and Minecraft Java 1.21/1.21.1. For more information, please see [here](https://geysermc.org/wiki/geyser/supported-versions/).
|
||||
Geyser is currently supporting Minecraft Bedrock 1.20.80 - 1.21.30 and Minecraft Java 1.21/1.21.1. For more information, please see [here](https://geysermc.org/wiki/geyser/supported-versions/).
|
||||
|
||||
## Setting Up
|
||||
Take a look [here](https://geysermc.org/wiki/geyser/setup/) for how to set up Geyser.
|
||||
|
|
|
@ -54,7 +54,7 @@ public enum GeyserAttributeType {
|
|||
|
||||
// Bedrock Attributes
|
||||
ABSORPTION(null, "minecraft:absorption", 0f, 1024f, 0f),
|
||||
EXHAUSTION(null, "minecraft:player.exhaustion", 0f, 5f, 0f),
|
||||
EXHAUSTION(null, "minecraft:player.exhaustion", 0f, 20f, 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),
|
||||
|
|
|
@ -43,13 +43,13 @@ public class CameraDefinitions {
|
|||
|
||||
static {
|
||||
CAMERA_PRESETS = List.of(
|
||||
new CameraPreset(CameraPerspective.FIRST_PERSON.id(), "", null, null, null, null, null, null, OptionalBoolean.empty()),
|
||||
new CameraPreset(CameraPerspective.FREE.id(), "", null, null, null, null, null, null, OptionalBoolean.empty()),
|
||||
new CameraPreset(CameraPerspective.THIRD_PERSON.id(), "", null, null, null, null, null, null, OptionalBoolean.empty()),
|
||||
new CameraPreset(CameraPerspective.THIRD_PERSON_FRONT.id(), "", null, null, null, null, null, null, OptionalBoolean.empty()),
|
||||
new CameraPreset("geyser:free_audio", "minecraft:free", null, null, null, null, null, CameraAudioListener.PLAYER, OptionalBoolean.of(false)),
|
||||
new CameraPreset("geyser:free_effects", "minecraft:free", null, null, null, null, null, CameraAudioListener.CAMERA, OptionalBoolean.of(true)),
|
||||
new CameraPreset("geyser:free_audio_effects", "minecraft:free", null, null, null, null, null, CameraAudioListener.PLAYER, OptionalBoolean.of(true)));
|
||||
new CameraPreset(CameraPerspective.FIRST_PERSON.id(), "", null, null, null, null, null, null, OptionalBoolean.empty(), null, OptionalBoolean.empty(), null),
|
||||
new CameraPreset(CameraPerspective.FREE.id(), "", null, null, null, null, null, null, OptionalBoolean.empty(), null, OptionalBoolean.empty(), null),
|
||||
new CameraPreset(CameraPerspective.THIRD_PERSON.id(), "", null, null, null, null, null, null, OptionalBoolean.empty(), null, OptionalBoolean.empty(), null),
|
||||
new CameraPreset(CameraPerspective.THIRD_PERSON_FRONT.id(), "", null, null, null, null, null, null, OptionalBoolean.empty(), null, OptionalBoolean.empty(), null),
|
||||
new CameraPreset("geyser:free_audio", "minecraft:free", null, null, null, null, null, CameraAudioListener.PLAYER, OptionalBoolean.empty(), null, OptionalBoolean.of(false), null),
|
||||
new CameraPreset("geyser:free_effects", "minecraft:free", null, null, null, null, null, CameraAudioListener.CAMERA, OptionalBoolean.empty(), null, OptionalBoolean.of(true), null),
|
||||
new CameraPreset("geyser:free_audio_effects", "minecraft:free", null, null, null, null, null, CameraAudioListener.PLAYER, OptionalBoolean.empty(), null, OptionalBoolean.of(true), null));
|
||||
|
||||
SimpleDefinitionRegistry.Builder<NamedDefinition> builder = SimpleDefinitionRegistry.builder();
|
||||
for (int i = 0; i < CAMERA_PRESETS.size(); i++) {
|
||||
|
|
|
@ -32,6 +32,8 @@ import net.kyori.adventure.text.Component;
|
|||
import org.cloudburstmc.nbt.NbtMap;
|
||||
import org.cloudburstmc.nbt.NbtMapBuilder;
|
||||
import org.cloudburstmc.protocol.bedrock.data.inventory.ContainerId;
|
||||
import org.cloudburstmc.protocol.bedrock.data.inventory.ContainerSlotType;
|
||||
import org.cloudburstmc.protocol.bedrock.data.inventory.FullContainerName;
|
||||
import org.cloudburstmc.protocol.bedrock.data.inventory.ItemData;
|
||||
import org.cloudburstmc.protocol.bedrock.packet.InventorySlotPacket;
|
||||
import org.geysermc.geyser.GeyserImpl;
|
||||
|
@ -78,6 +80,7 @@ public class AnvilInventoryUpdater extends InventoryUpdater {
|
|||
slotPacket.setContainerId(ContainerId.UI);
|
||||
slotPacket.setSlot(bedrockSlot);
|
||||
slotPacket.setItem(inventory.getItem(i).getItemData(session));
|
||||
slotPacket.setContainerNameData(new FullContainerName(ContainerSlotType.ANVIL_INPUT, null));
|
||||
session.sendUpstreamPacket(slotPacket);
|
||||
}
|
||||
}
|
||||
|
@ -98,6 +101,7 @@ public class AnvilInventoryUpdater extends InventoryUpdater {
|
|||
slotPacket.setContainerId(ContainerId.UI);
|
||||
slotPacket.setSlot(translator.javaSlotToBedrock(javaSlot));
|
||||
slotPacket.setItem(inventory.getItem(javaSlot).getItemData(session));
|
||||
slotPacket.setContainerNameData(new FullContainerName(ContainerSlotType.ANVIL_INPUT, null));
|
||||
session.sendUpstreamPacket(slotPacket);
|
||||
} else if (lastTargetSlot != javaSlot) {
|
||||
// Update the previous target slot to remove repair cost changes
|
||||
|
@ -105,6 +109,7 @@ public class AnvilInventoryUpdater extends InventoryUpdater {
|
|||
slotPacket.setContainerId(ContainerId.UI);
|
||||
slotPacket.setSlot(translator.javaSlotToBedrock(lastTargetSlot));
|
||||
slotPacket.setItem(inventory.getItem(lastTargetSlot).getItemData(session));
|
||||
slotPacket.setContainerNameData(new FullContainerName(ContainerSlotType.ANVIL_INPUT, null));
|
||||
session.sendUpstreamPacket(slotPacket);
|
||||
}
|
||||
|
||||
|
@ -168,6 +173,7 @@ public class AnvilInventoryUpdater extends InventoryUpdater {
|
|||
slotPacket.setContainerId(ContainerId.UI);
|
||||
slotPacket.setSlot(translator.javaSlotToBedrock(slot));
|
||||
slotPacket.setItem(itemData);
|
||||
slotPacket.setContainerNameData(new FullContainerName(ContainerSlotType.ANVIL_INPUT, null));
|
||||
session.sendUpstreamPacket(slotPacket);
|
||||
}
|
||||
|
||||
|
|
|
@ -25,6 +25,8 @@
|
|||
|
||||
package org.geysermc.geyser.inventory.updater;
|
||||
|
||||
import org.cloudburstmc.protocol.bedrock.data.inventory.ContainerSlotType;
|
||||
import org.cloudburstmc.protocol.bedrock.data.inventory.FullContainerName;
|
||||
import org.cloudburstmc.protocol.bedrock.data.inventory.ItemData;
|
||||
import org.cloudburstmc.protocol.bedrock.packet.InventoryContentPacket;
|
||||
import org.cloudburstmc.protocol.bedrock.packet.InventorySlotPacket;
|
||||
|
@ -61,6 +63,7 @@ public class ChestInventoryUpdater extends InventoryUpdater {
|
|||
InventoryContentPacket contentPacket = new InventoryContentPacket();
|
||||
contentPacket.setContainerId(inventory.getBedrockId());
|
||||
contentPacket.setContents(bedrockItems);
|
||||
contentPacket.setContainerNameData(new FullContainerName(ContainerSlotType.ANVIL_INPUT, null));
|
||||
session.sendUpstreamPacket(contentPacket);
|
||||
}
|
||||
|
||||
|
@ -73,6 +76,7 @@ public class ChestInventoryUpdater extends InventoryUpdater {
|
|||
slotPacket.setContainerId(inventory.getBedrockId());
|
||||
slotPacket.setSlot(translator.javaSlotToBedrock(javaSlot));
|
||||
slotPacket.setItem(inventory.getItem(javaSlot).getItemData(session));
|
||||
slotPacket.setContainerNameData(new FullContainerName(ContainerSlotType.ANVIL_INPUT, null));
|
||||
session.sendUpstreamPacket(slotPacket);
|
||||
return true;
|
||||
}
|
||||
|
|
|
@ -25,6 +25,8 @@
|
|||
|
||||
package org.geysermc.geyser.inventory.updater;
|
||||
|
||||
import org.cloudburstmc.protocol.bedrock.data.inventory.ContainerSlotType;
|
||||
import org.cloudburstmc.protocol.bedrock.data.inventory.FullContainerName;
|
||||
import org.cloudburstmc.protocol.bedrock.data.inventory.ItemData;
|
||||
import org.cloudburstmc.protocol.bedrock.packet.InventoryContentPacket;
|
||||
import org.cloudburstmc.protocol.bedrock.packet.InventorySlotPacket;
|
||||
|
@ -49,6 +51,7 @@ public class ContainerInventoryUpdater extends InventoryUpdater {
|
|||
InventoryContentPacket contentPacket = new InventoryContentPacket();
|
||||
contentPacket.setContainerId(inventory.getBedrockId());
|
||||
contentPacket.setContents(Arrays.asList(bedrockItems));
|
||||
contentPacket.setContainerNameData(new FullContainerName(ContainerSlotType.ANVIL_INPUT, null));
|
||||
session.sendUpstreamPacket(contentPacket);
|
||||
}
|
||||
|
||||
|
@ -61,6 +64,7 @@ public class ContainerInventoryUpdater extends InventoryUpdater {
|
|||
slotPacket.setContainerId(inventory.getBedrockId());
|
||||
slotPacket.setSlot(translator.javaSlotToBedrock(javaSlot));
|
||||
slotPacket.setItem(inventory.getItem(javaSlot).getItemData(session));
|
||||
slotPacket.setContainerNameData(new FullContainerName(ContainerSlotType.ANVIL_INPUT, null));
|
||||
session.sendUpstreamPacket(slotPacket);
|
||||
return true;
|
||||
}
|
||||
|
|
|
@ -26,6 +26,8 @@
|
|||
package org.geysermc.geyser.inventory.updater;
|
||||
|
||||
import org.cloudburstmc.protocol.bedrock.data.inventory.ContainerId;
|
||||
import org.cloudburstmc.protocol.bedrock.data.inventory.ContainerSlotType;
|
||||
import org.cloudburstmc.protocol.bedrock.data.inventory.FullContainerName;
|
||||
import org.cloudburstmc.protocol.bedrock.data.inventory.ItemData;
|
||||
import org.cloudburstmc.protocol.bedrock.packet.InventoryContentPacket;
|
||||
import org.cloudburstmc.protocol.bedrock.packet.InventorySlotPacket;
|
||||
|
@ -56,6 +58,7 @@ public class CrafterInventoryUpdater extends InventoryUpdater {
|
|||
contentPacket = new InventoryContentPacket();
|
||||
contentPacket.setContainerId(inventory.getBedrockId());
|
||||
contentPacket.setContents(Arrays.asList(bedrockItems));
|
||||
contentPacket.setContainerNameData(new FullContainerName(ContainerSlotType.ANVIL_INPUT, null));
|
||||
session.sendUpstreamPacket(contentPacket);
|
||||
|
||||
// inventory and hotbar
|
||||
|
@ -67,6 +70,7 @@ public class CrafterInventoryUpdater extends InventoryUpdater {
|
|||
contentPacket = new InventoryContentPacket();
|
||||
contentPacket.setContainerId(ContainerId.INVENTORY);
|
||||
contentPacket.setContents(Arrays.asList(bedrockItems));
|
||||
contentPacket.setContainerNameData(new FullContainerName(ContainerSlotType.ANVIL_INPUT, null));
|
||||
session.sendUpstreamPacket(contentPacket);
|
||||
|
||||
// Crafter result - it doesn't come after the grid, as explained elsewhere.
|
||||
|
@ -88,6 +92,7 @@ public class CrafterInventoryUpdater extends InventoryUpdater {
|
|||
packet.setContainerId(containerId);
|
||||
packet.setSlot(translator.javaSlotToBedrock(javaSlot));
|
||||
packet.setItem(inventory.getItem(javaSlot).getItemData(session));
|
||||
packet.setContainerNameData(new FullContainerName(ContainerSlotType.ANVIL_INPUT, null));
|
||||
session.sendUpstreamPacket(packet);
|
||||
return true;
|
||||
}
|
||||
|
|
|
@ -25,6 +25,8 @@
|
|||
|
||||
package org.geysermc.geyser.inventory.updater;
|
||||
|
||||
import org.cloudburstmc.protocol.bedrock.data.inventory.ContainerSlotType;
|
||||
import org.cloudburstmc.protocol.bedrock.data.inventory.FullContainerName;
|
||||
import org.cloudburstmc.protocol.bedrock.data.inventory.ItemData;
|
||||
import org.cloudburstmc.protocol.bedrock.packet.InventoryContentPacket;
|
||||
import org.cloudburstmc.protocol.bedrock.packet.InventorySlotPacket;
|
||||
|
@ -49,6 +51,7 @@ public class HorseInventoryUpdater extends InventoryUpdater {
|
|||
InventoryContentPacket contentPacket = new InventoryContentPacket();
|
||||
contentPacket.setContainerId(inventory.getBedrockId());
|
||||
contentPacket.setContents(Arrays.asList(bedrockItems));
|
||||
contentPacket.setContainerNameData(new FullContainerName(ContainerSlotType.ANVIL_INPUT, null));
|
||||
session.sendUpstreamPacket(contentPacket);
|
||||
}
|
||||
|
||||
|
@ -61,6 +64,7 @@ public class HorseInventoryUpdater extends InventoryUpdater {
|
|||
slotPacket.setContainerId(4); // Horse GUI?
|
||||
slotPacket.setSlot(translator.javaSlotToBedrock(javaSlot));
|
||||
slotPacket.setItem(inventory.getItem(javaSlot).getItemData(session));
|
||||
slotPacket.setContainerNameData(new FullContainerName(ContainerSlotType.ANVIL_INPUT, null));
|
||||
session.sendUpstreamPacket(slotPacket);
|
||||
return true;
|
||||
}
|
||||
|
|
|
@ -26,6 +26,8 @@
|
|||
package org.geysermc.geyser.inventory.updater;
|
||||
|
||||
import org.cloudburstmc.protocol.bedrock.data.inventory.ContainerId;
|
||||
import org.cloudburstmc.protocol.bedrock.data.inventory.ContainerSlotType;
|
||||
import org.cloudburstmc.protocol.bedrock.data.inventory.FullContainerName;
|
||||
import org.cloudburstmc.protocol.bedrock.data.inventory.ItemData;
|
||||
import org.cloudburstmc.protocol.bedrock.packet.InventoryContentPacket;
|
||||
import org.cloudburstmc.protocol.bedrock.packet.InventorySlotPacket;
|
||||
|
@ -45,6 +47,7 @@ public class InventoryUpdater {
|
|||
InventoryContentPacket contentPacket = new InventoryContentPacket();
|
||||
contentPacket.setContainerId(ContainerId.INVENTORY);
|
||||
contentPacket.setContents(Arrays.asList(bedrockItems));
|
||||
contentPacket.setContainerNameData(new FullContainerName(ContainerSlotType.ANVIL_INPUT, null));
|
||||
session.sendUpstreamPacket(contentPacket);
|
||||
}
|
||||
|
||||
|
@ -54,6 +57,7 @@ public class InventoryUpdater {
|
|||
slotPacket.setContainerId(ContainerId.INVENTORY);
|
||||
slotPacket.setSlot(translator.javaSlotToBedrock(javaSlot));
|
||||
slotPacket.setItem(inventory.getItem(javaSlot).getItemData(session));
|
||||
slotPacket.setContainerNameData(new FullContainerName(ContainerSlotType.ANVIL_INPUT, null));
|
||||
session.sendUpstreamPacket(slotPacket);
|
||||
return true;
|
||||
}
|
||||
|
|
|
@ -26,6 +26,8 @@
|
|||
package org.geysermc.geyser.inventory.updater;
|
||||
|
||||
import org.cloudburstmc.protocol.bedrock.data.inventory.ContainerId;
|
||||
import org.cloudburstmc.protocol.bedrock.data.inventory.ContainerSlotType;
|
||||
import org.cloudburstmc.protocol.bedrock.data.inventory.FullContainerName;
|
||||
import org.cloudburstmc.protocol.bedrock.packet.InventorySlotPacket;
|
||||
import org.geysermc.geyser.inventory.Inventory;
|
||||
import org.geysermc.geyser.session.GeyserSession;
|
||||
|
@ -46,6 +48,7 @@ public class UIInventoryUpdater extends InventoryUpdater {
|
|||
slotPacket.setContainerId(ContainerId.UI);
|
||||
slotPacket.setSlot(bedrockSlot);
|
||||
slotPacket.setItem(inventory.getItem(i).getItemData(session));
|
||||
slotPacket.setContainerNameData(new FullContainerName(ContainerSlotType.ANVIL_INPUT, null));
|
||||
session.sendUpstreamPacket(slotPacket);
|
||||
}
|
||||
}
|
||||
|
@ -59,6 +62,7 @@ public class UIInventoryUpdater extends InventoryUpdater {
|
|||
slotPacket.setContainerId(ContainerId.UI);
|
||||
slotPacket.setSlot(translator.javaSlotToBedrock(javaSlot));
|
||||
slotPacket.setItem(inventory.getItem(javaSlot).getItemData(session));
|
||||
slotPacket.setContainerNameData(new FullContainerName(ContainerSlotType.ANVIL_INPUT, null));
|
||||
session.sendUpstreamPacket(slotPacket);
|
||||
return true;
|
||||
}
|
||||
|
|
|
@ -25,8 +25,7 @@
|
|||
|
||||
package org.geysermc.geyser.item.enchantment;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.function.Function;
|
||||
import it.unimi.dsi.fastutil.ints.IntArrays;
|
||||
import net.kyori.adventure.key.Key;
|
||||
import org.checkerframework.checker.nullness.qual.Nullable;
|
||||
import org.cloudburstmc.nbt.NbtMap;
|
||||
|
@ -35,11 +34,14 @@ import org.geysermc.geyser.item.Items;
|
|||
import org.geysermc.geyser.registry.Registries;
|
||||
import org.geysermc.geyser.session.cache.registry.RegistryEntryContext;
|
||||
import org.geysermc.geyser.translator.text.MessageTranslator;
|
||||
import org.geysermc.geyser.util.MinecraftKey;
|
||||
import org.geysermc.mcprotocollib.protocol.data.game.item.component.HolderSet;
|
||||
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import org.geysermc.mcprotocollib.protocol.data.game.item.component.HolderSet;
|
||||
import java.util.function.ToIntFunction;
|
||||
|
||||
/**
|
||||
* @param description only populated if {@link #bedrockEnchantment()} is not null.
|
||||
|
@ -69,7 +71,7 @@ public record Enchantment(String identifier,
|
|||
|
||||
// TODO - description is a component. So if a hardcoded literal string is given, this will display normally on Java,
|
||||
// but Geyser will attempt to lookup the literal string as translation - and will fail, displaying an empty string as enchantment name.
|
||||
String description = bedrockEnchantment == null ? MessageTranslator.deserializeDescription(data) : null;
|
||||
String description = bedrockEnchantment == null ? MessageTranslator.deserializeDescription(context.session(), data) : null;
|
||||
|
||||
return new Enchantment(context.id().asString(), effects, supportedItems, maxLevel,
|
||||
description, anvilCost, exclusiveSet, bedrockEnchantment);
|
||||
|
@ -86,21 +88,21 @@ public record Enchantment(String identifier,
|
|||
}
|
||||
|
||||
// TODO holder set util?
|
||||
private static HolderSet readHolderSet(@Nullable Object holderSet, Function<Key, Integer> keyIdMapping) {
|
||||
private static HolderSet readHolderSet(@Nullable Object holderSet, ToIntFunction<Key> keyIdMapping) {
|
||||
if (holderSet == null) {
|
||||
return new HolderSet(new int[]{});
|
||||
return new HolderSet(IntArrays.EMPTY_ARRAY);
|
||||
}
|
||||
|
||||
if (holderSet instanceof String stringTag) {
|
||||
// Tag
|
||||
if (stringTag.startsWith("#")) {
|
||||
return new HolderSet(Key.key(stringTag.substring(1))); // Remove '#' at beginning that indicates tag
|
||||
return new HolderSet(MinecraftKey.key(stringTag.substring(1))); // Remove '#' at beginning that indicates tag
|
||||
} else {
|
||||
return new HolderSet(new int[]{keyIdMapping.apply(Key.key(stringTag))});
|
||||
return new HolderSet(new int[]{keyIdMapping.applyAsInt(MinecraftKey.key(stringTag))});
|
||||
}
|
||||
} else if (holderSet instanceof List<?> list) {
|
||||
// Assume the list is a list of strings
|
||||
return new HolderSet(list.stream().map(o -> (String) o).map(Key::key).map(keyIdMapping).mapToInt(Integer::intValue).toArray());
|
||||
return new HolderSet(list.stream().map(o -> (String) o).map(Key::key).mapToInt(keyIdMapping).toArray());
|
||||
}
|
||||
throw new IllegalArgumentException("Holder set must either be a tag, a string ID or a list of string IDs");
|
||||
}
|
||||
|
|
|
@ -44,7 +44,7 @@ public record JukeboxSong(String soundEvent, String description) {
|
|||
soundEvent = "";
|
||||
GeyserImpl.getInstance().getLogger().debug("Sound event for " + context.id() + " was of an unexpected type! Expected string or NBT map, got " + soundEventObject);
|
||||
}
|
||||
String description = MessageTranslator.deserializeDescription(data);
|
||||
String description = MessageTranslator.deserializeDescription(context.session(), data);
|
||||
return new JukeboxSong(soundEvent, description);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -33,7 +33,6 @@ import org.cloudburstmc.protocol.bedrock.codec.v291.serializer.MobArmorEquipment
|
|||
import org.cloudburstmc.protocol.bedrock.codec.v291.serializer.MobEquipmentSerializer_v291;
|
||||
import org.cloudburstmc.protocol.bedrock.codec.v291.serializer.PlayerHotbarSerializer_v291;
|
||||
import org.cloudburstmc.protocol.bedrock.codec.v291.serializer.SetEntityLinkSerializer_v291;
|
||||
import org.cloudburstmc.protocol.bedrock.codec.v291.serializer.SetEntityMotionSerializer_v291;
|
||||
import org.cloudburstmc.protocol.bedrock.codec.v390.serializer.PlayerSkinSerializer_v390;
|
||||
import org.cloudburstmc.protocol.bedrock.codec.v407.serializer.InventoryContentSerializer_v407;
|
||||
import org.cloudburstmc.protocol.bedrock.codec.v407.serializer.InventorySlotSerializer_v407;
|
||||
|
@ -43,6 +42,8 @@ import org.cloudburstmc.protocol.bedrock.codec.v662.serializer.SetEntityMotionSe
|
|||
import org.cloudburstmc.protocol.bedrock.codec.v712.serializer.InventoryContentSerializer_v712;
|
||||
import org.cloudburstmc.protocol.bedrock.codec.v712.serializer.InventorySlotSerializer_v712;
|
||||
import org.cloudburstmc.protocol.bedrock.codec.v712.serializer.MobArmorEquipmentSerializer_v712;
|
||||
import org.cloudburstmc.protocol.bedrock.codec.v729.serializer.InventoryContentSerializer_v729;
|
||||
import org.cloudburstmc.protocol.bedrock.codec.v729.serializer.InventorySlotSerializer_v729;
|
||||
import org.cloudburstmc.protocol.bedrock.packet.AnvilDamagePacket;
|
||||
import org.cloudburstmc.protocol.bedrock.packet.BedrockPacket;
|
||||
import org.cloudburstmc.protocol.bedrock.packet.BossEventPacket;
|
||||
|
@ -139,6 +140,13 @@ class CodecProcessor {
|
|||
}
|
||||
};
|
||||
|
||||
private static final BedrockPacketSerializer<InventoryContentPacket> INVENTORY_CONTENT_SERIALIZER_V729 = new InventoryContentSerializer_v729() {
|
||||
@Override
|
||||
public void deserialize(ByteBuf buffer, BedrockCodecHelper helper, InventoryContentPacket packet) {
|
||||
throw new IllegalArgumentException("Client cannot send InventoryContentPacket in server-auth inventory environment!");
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Serializer that throws an exception when trying to deserialize InventorySlotPacket since server-auth inventory is used.
|
||||
*/
|
||||
|
@ -159,6 +167,13 @@ class CodecProcessor {
|
|||
}
|
||||
};
|
||||
|
||||
private static final BedrockPacketSerializer<InventorySlotPacket> INVENTORY_SLOT_SERIALIZER_V729 = new InventorySlotSerializer_v729() {
|
||||
@Override
|
||||
public void deserialize(ByteBuf buffer, BedrockCodecHelper helper, InventorySlotPacket packet) {
|
||||
throw new IllegalArgumentException("Client cannot send InventorySlotPacket in server-auth inventory environment!");
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Serializer that does nothing when trying to deserialize BossEventPacket since it is not used from the client.
|
||||
*/
|
||||
|
@ -214,16 +229,7 @@ class CodecProcessor {
|
|||
};
|
||||
|
||||
/**
|
||||
* Serializer that does nothing when trying to deserialize SetEntityMotionPacket since it is not used from the client for codec v291.
|
||||
*/
|
||||
private static final BedrockPacketSerializer<SetEntityMotionPacket> SET_ENTITY_MOTION_SERIALIZER_V291 = new SetEntityMotionSerializer_v291() {
|
||||
@Override
|
||||
public void deserialize(ByteBuf buffer, BedrockCodecHelper helper, SetEntityMotionPacket packet) {
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Serializer that does nothing when trying to deserialize SetEntityMotionPacket since it is not used from the client for codec v662.
|
||||
* Serializer that does nothing when trying to deserialize SetEntityMotionPacket since it is not used from the client.
|
||||
*/
|
||||
private static final BedrockPacketSerializer<SetEntityMotionPacket> SET_ENTITY_MOTION_SERIALIZER = new SetEntityMotionSerializer_v662() {
|
||||
@Override
|
||||
|
@ -256,8 +262,27 @@ class CodecProcessor {
|
|||
|
||||
@SuppressWarnings("unchecked")
|
||||
static BedrockCodec processCodec(BedrockCodec codec) {
|
||||
boolean isPre712 = codec.getProtocolVersion() < 712;
|
||||
|
||||
boolean is729OrAbove = codec.getProtocolVersion() >= 729;
|
||||
boolean is712OrAbove = codec.getProtocolVersion() >= 712;
|
||||
|
||||
BedrockPacketSerializer<InventoryContentPacket> inventoryContentSerializer;
|
||||
if (is729OrAbove) {
|
||||
inventoryContentSerializer = INVENTORY_CONTENT_SERIALIZER_V729;
|
||||
} else if (is712OrAbove) {
|
||||
inventoryContentSerializer = INVENTORY_CONTENT_SERIALIZER_V712;
|
||||
} else {
|
||||
inventoryContentSerializer = INVENTORY_CONTENT_SERIALIZER_V407;
|
||||
}
|
||||
|
||||
BedrockPacketSerializer<InventorySlotPacket> inventorySlotSerializer;
|
||||
if (is729OrAbove) {
|
||||
inventorySlotSerializer = INVENTORY_SLOT_SERIALIZER_V729;
|
||||
} else if (is712OrAbove) {
|
||||
inventorySlotSerializer = INVENTORY_SLOT_SERIALIZER_V712;
|
||||
} else {
|
||||
inventorySlotSerializer = INVENTORY_SLOT_SERIALIZER_V407;
|
||||
}
|
||||
|
||||
BedrockCodec.Builder codecBuilder = codec.toBuilder()
|
||||
// Illegal unused serverbound EDU packets
|
||||
.updateSerializer(PhotoTransferPacket.class, ILLEGAL_SERIALIZER)
|
||||
|
@ -286,11 +311,11 @@ class CodecProcessor {
|
|||
.updateSerializer(AnvilDamagePacket.class, IGNORED_SERIALIZER)
|
||||
.updateSerializer(RefreshEntitlementsPacket.class, IGNORED_SERIALIZER)
|
||||
// Illegal when serverbound due to Geyser specific setup
|
||||
.updateSerializer(InventoryContentPacket.class, isPre712 ? INVENTORY_CONTENT_SERIALIZER_V407 : INVENTORY_CONTENT_SERIALIZER_V712)
|
||||
.updateSerializer(InventorySlotPacket.class, isPre712 ? INVENTORY_SLOT_SERIALIZER_V407 : INVENTORY_SLOT_SERIALIZER_V712)
|
||||
.updateSerializer(InventoryContentPacket.class, inventoryContentSerializer)
|
||||
.updateSerializer(InventorySlotPacket.class, inventorySlotSerializer)
|
||||
// Ignored only when serverbound
|
||||
.updateSerializer(BossEventPacket.class, BOSS_EVENT_SERIALIZER)
|
||||
.updateSerializer(MobArmorEquipmentPacket.class, isPre712 ? MOB_ARMOR_EQUIPMENT_SERIALIZER_V291 : MOB_ARMOR_EQUIPMENT_SERIALIZER_V712)
|
||||
.updateSerializer(MobArmorEquipmentPacket.class, is712OrAbove ? MOB_ARMOR_EQUIPMENT_SERIALIZER_V712 : MOB_ARMOR_EQUIPMENT_SERIALIZER_V291)
|
||||
.updateSerializer(PlayerHotbarPacket.class, PLAYER_HOTBAR_SERIALIZER)
|
||||
.updateSerializer(PlayerSkinPacket.class, PLAYER_SKIN_SERIALIZER)
|
||||
.updateSerializer(SetEntityDataPacket.class, SET_ENTITY_DATA_SERIALIZER)
|
||||
|
|
|
@ -31,6 +31,7 @@ import org.cloudburstmc.protocol.bedrock.codec.v671.Bedrock_v671;
|
|||
import org.cloudburstmc.protocol.bedrock.codec.v685.Bedrock_v685;
|
||||
import org.cloudburstmc.protocol.bedrock.codec.v686.Bedrock_v686;
|
||||
import org.cloudburstmc.protocol.bedrock.codec.v712.Bedrock_v712;
|
||||
import org.cloudburstmc.protocol.bedrock.codec.v729.Bedrock_v729;
|
||||
import org.cloudburstmc.protocol.bedrock.netty.codec.packet.BedrockPacketCodec;
|
||||
import org.geysermc.geyser.session.GeyserSession;
|
||||
import org.geysermc.mcprotocollib.protocol.codec.MinecraftCodec;
|
||||
|
@ -49,8 +50,8 @@ public final class GameProtocol {
|
|||
* Default Bedrock codec that should act as a fallback. Should represent the latest available
|
||||
* release of the game that Geyser supports.
|
||||
*/
|
||||
public static final BedrockCodec DEFAULT_BEDROCK_CODEC = CodecProcessor.processCodec(Bedrock_v712.CODEC.toBuilder()
|
||||
.minecraftVersion("1.21.20/1.21.21")
|
||||
public static final BedrockCodec DEFAULT_BEDROCK_CODEC = CodecProcessor.processCodec(Bedrock_v729.CODEC.toBuilder()
|
||||
.minecraftVersion("1.21.30")
|
||||
.build());
|
||||
|
||||
/**
|
||||
|
@ -74,6 +75,9 @@ public final class GameProtocol {
|
|||
SUPPORTED_BEDROCK_CODECS.add(CodecProcessor.processCodec(Bedrock_v686.CODEC.toBuilder()
|
||||
.minecraftVersion("1.21.2/1.21.3")
|
||||
.build()));
|
||||
SUPPORTED_BEDROCK_CODECS.add(CodecProcessor.processCodec(Bedrock_v712.CODEC.toBuilder()
|
||||
.minecraftVersion("1.21.20 - 1.21.23")
|
||||
.build()));
|
||||
SUPPORTED_BEDROCK_CODECS.add(DEFAULT_BEDROCK_CODEC);
|
||||
}
|
||||
|
||||
|
|
|
@ -48,6 +48,7 @@ import org.cloudburstmc.nbt.NbtUtils;
|
|||
import org.cloudburstmc.protocol.bedrock.codec.v671.Bedrock_v671;
|
||||
import org.cloudburstmc.protocol.bedrock.codec.v685.Bedrock_v685;
|
||||
import org.cloudburstmc.protocol.bedrock.codec.v712.Bedrock_v712;
|
||||
import org.cloudburstmc.protocol.bedrock.codec.v729.Bedrock_v729;
|
||||
import org.cloudburstmc.protocol.bedrock.data.BlockPropertyData;
|
||||
import org.cloudburstmc.protocol.bedrock.data.definitions.BlockDefinition;
|
||||
import org.geysermc.geyser.GeyserImpl;
|
||||
|
@ -128,7 +129,8 @@ public final class BlockRegistryPopulator {
|
|||
var blockMappers = ImmutableMap.<ObjectIntPair<String>, Remapper>builder()
|
||||
.put(ObjectIntPair.of("1_20_80", Bedrock_v671.CODEC.getProtocolVersion()), Conversion685_671::remapBlock)
|
||||
.put(ObjectIntPair.of("1_21_0", Bedrock_v685.CODEC.getProtocolVersion()), Conversion712_685::remapBlock)
|
||||
.put(ObjectIntPair.of("1_21_20", Bedrock_v712.CODEC.getProtocolVersion()), tag -> tag)
|
||||
.put(ObjectIntPair.of("1_21_20", Bedrock_v712.CODEC.getProtocolVersion()), Conversion729_712::remapBlock)
|
||||
.put(ObjectIntPair.of("1_21_30", Bedrock_v729.CODEC.getProtocolVersion()), tag -> tag)
|
||||
.build();
|
||||
|
||||
// We can keep this strong as nothing should be garbage collected
|
||||
|
|
|
@ -32,6 +32,8 @@ public class Conversion712_685 {
|
|||
private static final List<String> NEW_BLOCKS = Stream.of(NEW_STONE_BLOCK_SLABS_2, NEW_STONE_BLOCK_SLABS_3, NEW_STONE_BLOCK_SLABS_4, NEW_DOUBLE_STONE_BLOCK_SLABS, NEW_DOUBLE_STONE_BLOCK_SLABS_2, NEW_DOUBLE_STONE_BLOCK_SLABS_3, NEW_DOUBLE_STONE_BLOCK_SLABS_4, NEW_PRISMARINE_BLOCKS, NEW_CORAL_FAN_HANGS, NEW_CORAL_FAN_HANGS_2, NEW_CORAL_FAN_HANGS_3, NEW_MONSTER_EGGS, NEW_STONEBRICK_BLOCKS, NEW_LIGHT_BLOCKS, NEW_SANDSTONE_BLOCKS, NEW_QUARTZ_BLOCKS, NEW_RED_SANDSTONE_BLOCKS, NEW_SAND_BLOCKS, NEW_DIRT_BLOCKS, NEW_ANVILS, NEW_YELLOW_FLOWERS).flatMap(List::stream).toList();
|
||||
|
||||
static GeyserMappingItem remapItem(Item item, GeyserMappingItem mapping) {
|
||||
mapping = Conversion729_712.remapItem(item, mapping);
|
||||
|
||||
String identifer = mapping.getBedrockIdentifier();
|
||||
|
||||
if (!NEW_BLOCKS.contains(identifer)) {
|
||||
|
@ -153,6 +155,8 @@ public class Conversion712_685 {
|
|||
}
|
||||
|
||||
static NbtMap remapBlock(NbtMap tag) {
|
||||
tag = Conversion729_712.remapBlock(tag);
|
||||
|
||||
final String name = tag.getString("name");
|
||||
|
||||
if (!NEW_BLOCKS.contains(name)) {
|
||||
|
|
|
@ -0,0 +1,151 @@
|
|||
package org.geysermc.geyser.registry.populator;
|
||||
|
||||
import org.cloudburstmc.nbt.NbtMap;
|
||||
import org.geysermc.geyser.item.type.Item;
|
||||
import org.geysermc.geyser.registry.type.GeyserMappingItem;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
public class Conversion729_712 {
|
||||
private static final List<String> NEW_PURPUR_BLOCKS = List.of("minecraft:purpur_block", "minecraft:purpur_pillar");
|
||||
private static final List<String> NEW_WALL_BLOCKS = List.of("minecraft:cobblestone_wall", "minecraft:mossy_cobblestone_wall", "minecraft:granite_wall", "minecraft:diorite_wall", "minecraft:andesite_wall", "minecraft:sandstone_wall", "minecraft:brick_wall", "minecraft:stone_brick_wall", "minecraft:mossy_stone_brick_wall", "minecraft:nether_brick_wall", "minecraft:end_stone_brick_wall", "minecraft:prismarine_wall", "minecraft:red_sandstone_wall", "minecraft:red_nether_brick_wall");
|
||||
private static final List<String> NEW_SPONGE_BLOCKS = List.of("minecraft:sponge", "minecraft:wet_sponge");
|
||||
private static final List<String> NEW_TNT_BLOCKS = List.of("minecraft:tnt", "minecraft:underwater_tnt");
|
||||
private static final List<String> STRUCTURE_VOID = List.of("minecraft:structure_void");
|
||||
private static final List<String> NEW_BLOCKS = Stream.of(NEW_PURPUR_BLOCKS, NEW_WALL_BLOCKS, NEW_SPONGE_BLOCKS, NEW_TNT_BLOCKS, STRUCTURE_VOID).flatMap(List::stream).toList();
|
||||
|
||||
static GeyserMappingItem remapItem(Item item, GeyserMappingItem mapping) {
|
||||
String identifier = mapping.getBedrockIdentifier();
|
||||
|
||||
if (!NEW_BLOCKS.contains(identifier)) {
|
||||
return mapping;
|
||||
}
|
||||
|
||||
if (identifier.equals("minecraft:underwater_tnt")) {
|
||||
return mapping.withBedrockIdentifier("minecraft:tnt").withBedrockData(1);
|
||||
}
|
||||
|
||||
if (NEW_PURPUR_BLOCKS.contains(identifier)) {
|
||||
switch (identifier) {
|
||||
case "minecraft:purpur_block" -> { return mapping.withBedrockIdentifier("minecraft:purpur_block").withBedrockData(0); }
|
||||
case "minecraft:purpur_pillar" -> { return mapping.withBedrockIdentifier("minecraft:purpur_block").withBedrockData(1); }
|
||||
}
|
||||
}
|
||||
|
||||
if (NEW_WALL_BLOCKS.contains(identifier)) {
|
||||
switch (identifier) {
|
||||
case "minecraft:cobblestone_wall" -> { return mapping.withBedrockIdentifier("minecraft:cobblestone_wall").withBedrockData(0); }
|
||||
case "minecraft:mossy_cobblestone_wall" -> { return mapping.withBedrockIdentifier("minecraft:cobblestone_wall").withBedrockData(1); }
|
||||
case "minecraft:granite_wall" -> { return mapping.withBedrockIdentifier("minecraft:cobblestone_wall").withBedrockData(2); }
|
||||
case "minecraft:diorite_wall" -> { return mapping.withBedrockIdentifier("minecraft:cobblestone_wall").withBedrockData(3); }
|
||||
case "minecraft:andesite_wall" -> { return mapping.withBedrockIdentifier("minecraft:cobblestone_wall").withBedrockData(4); }
|
||||
case "minecraft:sandstone_wall" -> { return mapping.withBedrockIdentifier("minecraft:cobblestone_wall").withBedrockData(5); }
|
||||
case "minecraft:brick_wall" -> { return mapping.withBedrockIdentifier("minecraft:cobblestone_wall").withBedrockData(6); }
|
||||
case "minecraft:stone_brick_wall" -> { return mapping.withBedrockIdentifier("minecraft:cobblestone_wall").withBedrockData(7); }
|
||||
case "minecraft:mossy_stone_brick_wall" -> { return mapping.withBedrockIdentifier("minecraft:cobblestone_wall").withBedrockData(8); }
|
||||
case "minecraft:nether_brick_wall" -> { return mapping.withBedrockIdentifier("minecraft:cobblestone_wall").withBedrockData(9); }
|
||||
case "minecraft:end_stone_brick_wall" -> { return mapping.withBedrockIdentifier("minecraft:cobblestone_wall").withBedrockData(10); }
|
||||
case "minecraft:prismarine_wall" -> { return mapping.withBedrockIdentifier("minecraft:cobblestone_wall").withBedrockData(11); }
|
||||
case "minecraft:red_sandstone_wall" -> { return mapping.withBedrockIdentifier("minecraft:cobblestone_wall").withBedrockData(12); }
|
||||
case "minecraft:red_nether_brick_wall" -> { return mapping.withBedrockIdentifier("minecraft:cobblestone_wall").withBedrockData(13); }
|
||||
}
|
||||
}
|
||||
|
||||
if (NEW_SPONGE_BLOCKS.contains(identifier)) {
|
||||
switch (identifier) {
|
||||
case "minecraft:sponge" -> { return mapping.withBedrockIdentifier("minecraft:sponge").withBedrockData(0); }
|
||||
case "minecraft:wet_sponge" -> { return mapping.withBedrockIdentifier("minecraft:sponge").withBedrockData(1); }
|
||||
}
|
||||
}
|
||||
|
||||
return mapping;
|
||||
}
|
||||
|
||||
static NbtMap remapBlock(NbtMap tag) {
|
||||
final String name = tag.getString("name");
|
||||
|
||||
if (!NEW_BLOCKS.contains(name)) {
|
||||
return tag;
|
||||
}
|
||||
|
||||
String replacement;
|
||||
|
||||
if (NEW_PURPUR_BLOCKS.contains(name)) {
|
||||
replacement = "minecraft:purpur_block";
|
||||
String purpurType = name.equals("minecraft:purpur_pillar") ? "lines" : "default";
|
||||
|
||||
NbtMap states = tag.getCompound("states")
|
||||
.toBuilder()
|
||||
.putString("chisel_type", purpurType)
|
||||
.build();
|
||||
|
||||
return tag.toBuilder().putString("name", replacement).putCompound("states", states).build();
|
||||
}
|
||||
|
||||
if (NEW_WALL_BLOCKS.contains(name)) {
|
||||
replacement = "minecraft:cobblestone_wall";
|
||||
String wallType;
|
||||
|
||||
switch (name) {
|
||||
case "minecraft:cobblestone_wall" -> wallType = "cobblestone";
|
||||
case "minecraft:mossy_cobblestone_wall" -> wallType = "mossy_cobblestone";
|
||||
case "minecraft:granite_wall" -> wallType = "granite";
|
||||
case "minecraft:diorite_wall" -> wallType = "diorite";
|
||||
case "minecraft:andesite_wall" -> wallType = "andesite";
|
||||
case "minecraft:sandstone_wall" -> wallType = "sandstone";
|
||||
case "minecraft:brick_wall" -> wallType = "brick";
|
||||
case "minecraft:stone_brick_wall" -> wallType = "stone_brick";
|
||||
case "minecraft:mossy_stone_brick_wall" -> wallType = "mossy_stone_brick";
|
||||
case "minecraft:nether_brick_wall" -> wallType = "nether_brick";
|
||||
case "minecraft:end_stone_brick_wall" -> wallType = "end_brick";
|
||||
case "minecraft:prismarine_wall" -> wallType = "prismarine";
|
||||
case "minecraft:red_sandstone_wall" -> wallType = "red_sandstone";
|
||||
case "minecraft:red_nether_brick_wall" -> wallType = "red_nether_brick";
|
||||
default -> throw new IllegalStateException("Unexpected value: " + name);
|
||||
}
|
||||
|
||||
NbtMap states = tag.getCompound("states")
|
||||
.toBuilder()
|
||||
.putString("wall_block_type", wallType)
|
||||
.build();
|
||||
|
||||
return tag.toBuilder().putString("name", replacement).putCompound("states", states).build();
|
||||
}
|
||||
|
||||
if (NEW_SPONGE_BLOCKS.contains(name)) {
|
||||
replacement = "minecraft:sponge";
|
||||
String spongeType = name.equals("minecraft:wet_sponge") ? "wet" : "dry";
|
||||
|
||||
NbtMap states = tag.getCompound("states")
|
||||
.toBuilder()
|
||||
.putString("sponge_type", spongeType)
|
||||
.build();
|
||||
|
||||
return tag.toBuilder().putString("name", replacement).putCompound("states", states).build();
|
||||
}
|
||||
|
||||
if (NEW_TNT_BLOCKS.contains(name)) {
|
||||
replacement = "minecraft:tnt";
|
||||
byte tntType = (byte) (name.equals("minecraft:underwater_tnt") ? 1 : 0);
|
||||
|
||||
NbtMap states = tag.getCompound("states")
|
||||
.toBuilder()
|
||||
.putByte("allow_underwater_bit", tntType)
|
||||
.build();
|
||||
|
||||
return tag.toBuilder().putString("name", replacement).putCompound("states", states).build();
|
||||
}
|
||||
|
||||
if (STRUCTURE_VOID.contains(name)) {
|
||||
NbtMap states = tag.getCompound("states")
|
||||
.toBuilder()
|
||||
.putString("structure_void_type", "air")
|
||||
.build();
|
||||
|
||||
return tag.toBuilder().putCompound("states", states).build();
|
||||
}
|
||||
|
||||
return tag;
|
||||
}
|
||||
}
|
|
@ -48,6 +48,7 @@ import org.cloudburstmc.nbt.NbtUtils;
|
|||
import org.cloudburstmc.protocol.bedrock.codec.v671.Bedrock_v671;
|
||||
import org.cloudburstmc.protocol.bedrock.codec.v685.Bedrock_v685;
|
||||
import org.cloudburstmc.protocol.bedrock.codec.v712.Bedrock_v712;
|
||||
import org.cloudburstmc.protocol.bedrock.codec.v729.Bedrock_v729;
|
||||
import org.cloudburstmc.protocol.bedrock.data.definitions.BlockDefinition;
|
||||
import org.cloudburstmc.protocol.bedrock.data.definitions.ItemDefinition;
|
||||
import org.cloudburstmc.protocol.bedrock.data.definitions.SimpleItemDefinition;
|
||||
|
@ -112,7 +113,8 @@ public class ItemRegistryPopulator {
|
|||
List<PaletteVersion> paletteVersions = new ArrayList<>(3);
|
||||
paletteVersions.add(new PaletteVersion("1_20_80", Bedrock_v671.CODEC.getProtocolVersion(), Collections.emptyMap(), Conversion685_671::remapItem));
|
||||
paletteVersions.add(new PaletteVersion("1_21_0", Bedrock_v685.CODEC.getProtocolVersion(), Collections.emptyMap(), Conversion712_685::remapItem));
|
||||
paletteVersions.add(new PaletteVersion("1_21_20", Bedrock_v712.CODEC.getProtocolVersion()));
|
||||
paletteVersions.add(new PaletteVersion("1_21_20", Bedrock_v712.CODEC.getProtocolVersion(), Collections.emptyMap(), Conversion729_712::remapItem));
|
||||
paletteVersions.add(new PaletteVersion("1_21_30", Bedrock_v729.CODEC.getProtocolVersion()));
|
||||
|
||||
GeyserBootstrap bootstrap = GeyserImpl.getInstance().getBootstrap();
|
||||
|
||||
|
|
|
@ -568,14 +568,16 @@ public class GeyserSession implements GeyserConnection, GeyserCommandSource {
|
|||
private float walkSpeed;
|
||||
|
||||
/**
|
||||
* Caches current rain status.
|
||||
* Caches current rain strength.
|
||||
* Value between 0 and 1.
|
||||
*/
|
||||
private boolean raining = false;
|
||||
private float rainStrength = 0.0f;
|
||||
|
||||
/**
|
||||
* Caches current thunder status.
|
||||
* Caches current thunder strength.
|
||||
* Value between 0 and 1.
|
||||
*/
|
||||
private boolean thunder = false;
|
||||
private float thunderStrength = 0.0f;
|
||||
|
||||
/**
|
||||
* Stores a map of all statistics sent from the server.
|
||||
|
@ -2015,23 +2017,30 @@ public class GeyserSession implements GeyserConnection, GeyserCommandSource {
|
|||
* @param strength value between 0 and 1
|
||||
*/
|
||||
public void updateRain(float strength) {
|
||||
this.raining = strength > 0;
|
||||
boolean wasRaining = isRaining();
|
||||
this.rainStrength = strength;
|
||||
|
||||
LevelEventPacket rainPacket = new LevelEventPacket();
|
||||
rainPacket.setType(this.raining ? LevelEvent.START_RAINING : LevelEvent.STOP_RAINING);
|
||||
rainPacket.setType(isRaining() ? LevelEvent.START_RAINING : LevelEvent.STOP_RAINING);
|
||||
rainPacket.setData((int) (strength * 65535));
|
||||
rainPacket.setPosition(Vector3f.ZERO);
|
||||
sendUpstreamPacket(rainPacket);
|
||||
|
||||
if (this.raining) {
|
||||
sendUpstreamPacket(rainPacket);
|
||||
} else {
|
||||
// The bedrock client might ignore this packet if it is sent in the same tick as another rain packet
|
||||
// https://github.com/GeyserMC/Geyser/issues/3679
|
||||
scheduleInEventLoop(() -> {
|
||||
if (!this.raining) {
|
||||
sendUpstreamPacket(rainPacket);
|
||||
}
|
||||
}, 100, TimeUnit.MILLISECONDS);
|
||||
// Keep thunder in sync with rain when starting/stopping a storm
|
||||
if ((wasRaining != isRaining()) && isThunder()) {
|
||||
if (isRaining()) {
|
||||
LevelEventPacket thunderPacket = new LevelEventPacket();
|
||||
thunderPacket.setType(LevelEvent.START_THUNDERSTORM);
|
||||
thunderPacket.setData((int) (this.thunderStrength * 65535));
|
||||
thunderPacket.setPosition(Vector3f.ZERO);
|
||||
sendUpstreamPacket(thunderPacket);
|
||||
} else {
|
||||
LevelEventPacket thunderPacket = new LevelEventPacket();
|
||||
thunderPacket.setType(LevelEvent.STOP_THUNDERSTORM);
|
||||
thunderPacket.setData(0);
|
||||
thunderPacket.setPosition(Vector3f.ZERO);
|
||||
sendUpstreamPacket(thunderPacket);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -2042,24 +2051,28 @@ public class GeyserSession implements GeyserConnection, GeyserCommandSource {
|
|||
* @param strength value between 0 and 1
|
||||
*/
|
||||
public void updateThunder(float strength) {
|
||||
this.thunder = strength > 0;
|
||||
this.thunderStrength = strength;
|
||||
|
||||
// Do not send thunder packet if not raining
|
||||
// The bedrock client will start raining automatically when updating thunder strength
|
||||
// https://github.com/GeyserMC/Geyser/issues/3679
|
||||
if (!isRaining()) {
|
||||
return;
|
||||
}
|
||||
|
||||
LevelEventPacket thunderPacket = new LevelEventPacket();
|
||||
thunderPacket.setType(this.thunder ? LevelEvent.START_THUNDERSTORM : LevelEvent.STOP_THUNDERSTORM);
|
||||
thunderPacket.setType(isThunder() ? LevelEvent.START_THUNDERSTORM : LevelEvent.STOP_THUNDERSTORM);
|
||||
thunderPacket.setData((int) (strength * 65535));
|
||||
thunderPacket.setPosition(Vector3f.ZERO);
|
||||
sendUpstreamPacket(thunderPacket);
|
||||
}
|
||||
|
||||
if (this.thunder) {
|
||||
sendUpstreamPacket(thunderPacket);
|
||||
} else {
|
||||
// The bedrock client might ignore this packet if it is sent in the same tick as another thunderstorm packet
|
||||
// https://github.com/GeyserMC/Geyser/issues/3679
|
||||
scheduleInEventLoop(() -> {
|
||||
if (!this.thunder) {
|
||||
sendUpstreamPacket(thunderPacket);
|
||||
}
|
||||
}, 100, TimeUnit.MILLISECONDS);
|
||||
}
|
||||
public boolean isRaining() {
|
||||
return this.rainStrength > 0;
|
||||
}
|
||||
|
||||
public boolean isThunder() {
|
||||
return this.thunderStrength > 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -49,7 +49,7 @@ import org.geysermc.geyser.session.GeyserSession;
|
|||
import org.geysermc.geyser.session.cache.registry.JavaRegistry;
|
||||
import org.geysermc.geyser.session.cache.registry.RegistryEntryContext;
|
||||
import org.geysermc.geyser.session.cache.registry.SimpleJavaRegistry;
|
||||
import org.geysermc.geyser.text.TextDecoration;
|
||||
import org.geysermc.geyser.text.ChatDecoration;
|
||||
import org.geysermc.geyser.translator.level.BiomeTranslator;
|
||||
import org.geysermc.geyser.util.MinecraftKey;
|
||||
import org.geysermc.mcprotocollib.protocol.MinecraftProtocol;
|
||||
|
@ -78,7 +78,7 @@ public final class RegistryCache {
|
|||
private static final Map<Key, BiConsumer<RegistryCache, List<RegistryEntry>>> REGISTRIES = new HashMap<>();
|
||||
|
||||
static {
|
||||
register("chat_type", cache -> cache.chatTypes, TextDecoration::readChatType);
|
||||
register("chat_type", cache -> cache.chatTypes, ChatDecoration::readChatType);
|
||||
register("dimension_type", cache -> cache.dimensions, JavaDimension::read);
|
||||
register("enchantment", cache -> cache.enchantments, Enchantment::read);
|
||||
register("jukebox_song", cache -> cache.jukeboxSongs, JukeboxSong::read);
|
||||
|
|
|
@ -34,6 +34,7 @@ import lombok.Setter;
|
|||
import org.checkerframework.checker.nullness.qual.Nullable;
|
||||
import org.cloudburstmc.math.vector.Vector3i;
|
||||
import org.cloudburstmc.protocol.bedrock.packet.SetTitlePacket;
|
||||
import org.geysermc.geyser.item.type.Item;
|
||||
import org.geysermc.geyser.scoreboard.Scoreboard;
|
||||
import org.geysermc.geyser.scoreboard.ScoreboardUpdater.ScoreboardSession;
|
||||
import org.geysermc.geyser.session.GeyserSession;
|
||||
|
@ -70,6 +71,8 @@ public final class WorldCache {
|
|||
@Setter
|
||||
private boolean editingSignOnFront;
|
||||
|
||||
private final Object2IntMap<Item> activeCooldowns = new Object2IntOpenHashMap<>(2);
|
||||
|
||||
public WorldCache(GeyserSession session) {
|
||||
this.session = session;
|
||||
this.scoreboard = new Scoreboard(session);
|
||||
|
@ -201,4 +204,32 @@ public final class WorldCache {
|
|||
public String removeActiveRecord(Vector3i pos) {
|
||||
return this.activeRecords.remove(pos);
|
||||
}
|
||||
|
||||
public void setCooldown(Item item, int ticks) {
|
||||
if (ticks == 0) {
|
||||
// As of Java 1.21
|
||||
this.activeCooldowns.removeInt(item);
|
||||
return;
|
||||
}
|
||||
this.activeCooldowns.put(item, session.getTicks() + ticks);
|
||||
}
|
||||
|
||||
public boolean hasCooldown(Item item) {
|
||||
return this.activeCooldowns.containsKey(item);
|
||||
}
|
||||
|
||||
public void tick() {
|
||||
// Implementation note: technically we could empty the field during hasCooldown checks,
|
||||
// but we don't want the cooldown field to balloon in size from overuse.
|
||||
if (!this.activeCooldowns.isEmpty()) {
|
||||
int ticks = session.getTicks();
|
||||
Iterator<Object2IntMap.Entry<Item>> it = Object2IntMaps.fastIterator(this.activeCooldowns);
|
||||
while (it.hasNext()) {
|
||||
Object2IntMap.Entry<Item> entry = it.next();
|
||||
if (entry.getIntValue() <= ticks) {
|
||||
it.remove();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -25,17 +25,19 @@
|
|||
|
||||
package org.geysermc.geyser.text;
|
||||
|
||||
import net.kyori.adventure.text.format.NamedTextColor;
|
||||
import net.kyori.adventure.text.format.Style;
|
||||
import org.cloudburstmc.nbt.NbtMap;
|
||||
import org.cloudburstmc.nbt.NbtType;
|
||||
import org.geysermc.geyser.session.cache.registry.RegistryEntryContext;
|
||||
import org.geysermc.geyser.translator.text.MessageTranslator;
|
||||
import org.geysermc.mcprotocollib.protocol.data.game.chat.ChatType;
|
||||
import org.geysermc.mcprotocollib.protocol.data.game.chat.ChatTypeDecoration;
|
||||
|
||||
import java.util.*;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
|
||||
public record TextDecoration(String translationKey, List<Parameter> parameters, Style deserializedStyle) implements ChatTypeDecoration {
|
||||
public record ChatDecoration(String translationKey, List<Parameter> parameters, Style deserializedStyle) implements ChatTypeDecoration {
|
||||
|
||||
@Override
|
||||
public NbtMap style() {
|
||||
|
@ -53,38 +55,22 @@ public record TextDecoration(String translationKey, List<Parameter> parameters,
|
|||
String translationKey = chat.getString("translation_key");
|
||||
|
||||
NbtMap styleTag = chat.getCompound("style");
|
||||
Style style = deserializeStyle(styleTag);
|
||||
Style style = MessageTranslator.getStyleFromNbtMap(styleTag);
|
||||
|
||||
List<ChatTypeDecoration.Parameter> parameters = new ArrayList<>();
|
||||
List<String> parametersNbt = chat.getList("parameters", NbtType.STRING);
|
||||
for (String parameter : parametersNbt) {
|
||||
parameters.add(ChatTypeDecoration.Parameter.valueOf(parameter.toUpperCase(Locale.ROOT)));
|
||||
}
|
||||
return new ChatType(new TextDecoration(translationKey, parameters, style), null);
|
||||
return new ChatType(new ChatDecoration(translationKey, parameters, style), null);
|
||||
}
|
||||
return new ChatType(null, null);
|
||||
}
|
||||
|
||||
public static Style getStyle(ChatTypeDecoration decoration) {
|
||||
if (decoration instanceof TextDecoration textDecoration) {
|
||||
return textDecoration.deserializedStyle();
|
||||
if (decoration instanceof ChatDecoration chatDecoration) {
|
||||
return chatDecoration.deserializedStyle();
|
||||
}
|
||||
return deserializeStyle(decoration.style());
|
||||
}
|
||||
|
||||
private static Style deserializeStyle(NbtMap styleTag) {
|
||||
Style.Builder builder = Style.style();
|
||||
if (!styleTag.isEmpty()) {
|
||||
String color = styleTag.getString("color", null);
|
||||
if (color != null) {
|
||||
builder.color(NamedTextColor.NAMES.value(color));
|
||||
}
|
||||
//TODO implement the rest
|
||||
boolean italic = styleTag.getBoolean("italic");
|
||||
if (italic) {
|
||||
builder.decorate(net.kyori.adventure.text.format.TextDecoration.ITALIC);
|
||||
}
|
||||
}
|
||||
return builder.build();
|
||||
return MessageTranslator.getStyleFromNbtMap(decoration.style());
|
||||
}
|
||||
}
|
|
@ -981,11 +981,11 @@ public abstract class InventoryTranslator {
|
|||
|
||||
List<ItemStackResponseContainer> containerEntries = new ArrayList<>();
|
||||
for (Map.Entry<ContainerSlotType, List<ItemStackResponseSlot>> entry : containerMap.entrySet()) {
|
||||
containerEntries.add(new ItemStackResponseContainer(entry.getKey(), entry.getValue(), new FullContainerName(entry.getKey(), 0)));
|
||||
containerEntries.add(new ItemStackResponseContainer(entry.getKey(), entry.getValue(), new FullContainerName(entry.getKey(), null)));
|
||||
}
|
||||
|
||||
ItemStackResponseSlot cursorEntry = makeItemEntry(0, session.getPlayerInventory().getCursor());
|
||||
containerEntries.add(new ItemStackResponseContainer(ContainerSlotType.CURSOR, Collections.singletonList(cursorEntry), new FullContainerName(ContainerSlotType.CURSOR, 0)));
|
||||
containerEntries.add(new ItemStackResponseContainer(ContainerSlotType.CURSOR, Collections.singletonList(cursorEntry), new FullContainerName(ContainerSlotType.CURSOR, null)));
|
||||
|
||||
return containerEntries;
|
||||
}
|
||||
|
|
|
@ -28,6 +28,7 @@ package org.geysermc.geyser.translator.inventory;
|
|||
import org.cloudburstmc.protocol.bedrock.data.inventory.ContainerId;
|
||||
import org.cloudburstmc.protocol.bedrock.data.inventory.ContainerSlotType;
|
||||
import org.cloudburstmc.protocol.bedrock.data.inventory.ContainerType;
|
||||
import org.cloudburstmc.protocol.bedrock.data.inventory.FullContainerName;
|
||||
import org.cloudburstmc.protocol.bedrock.data.inventory.ItemData;
|
||||
import org.cloudburstmc.protocol.bedrock.data.inventory.itemstack.request.ItemStackRequest;
|
||||
import org.cloudburstmc.protocol.bedrock.data.inventory.itemstack.request.ItemStackRequestSlotData;
|
||||
|
@ -139,6 +140,7 @@ public class OldSmithingTableTranslator extends AbstractBlockInventoryTranslator
|
|||
slotPacket.setContainerId(ContainerId.UI);
|
||||
slotPacket.setSlot(53);
|
||||
slotPacket.setItem(UPGRADE_TEMPLATE.apply(session.getUpstream().getProtocolVersion()));
|
||||
slotPacket.setContainerNameData(new FullContainerName(ContainerSlotType.ANVIL_INPUT, null));
|
||||
session.sendUpstreamPacket(slotPacket);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -30,6 +30,7 @@ import it.unimi.dsi.fastutil.ints.IntOpenHashSet;
|
|||
import it.unimi.dsi.fastutil.ints.IntSet;
|
||||
import org.cloudburstmc.protocol.bedrock.data.inventory.ContainerId;
|
||||
import org.cloudburstmc.protocol.bedrock.data.inventory.ContainerSlotType;
|
||||
import org.cloudburstmc.protocol.bedrock.data.inventory.FullContainerName;
|
||||
import org.cloudburstmc.protocol.bedrock.data.inventory.ItemData;
|
||||
import org.cloudburstmc.protocol.bedrock.data.inventory.itemstack.request.ItemStackRequest;
|
||||
import org.cloudburstmc.protocol.bedrock.data.inventory.itemstack.request.ItemStackRequestSlotData;
|
||||
|
@ -83,6 +84,7 @@ public class PlayerInventoryTranslator extends InventoryTranslator {
|
|||
contents[i - 36] = inventory.getItem(i).getItemData(session);
|
||||
}
|
||||
inventoryContentPacket.setContents(Arrays.asList(contents));
|
||||
inventoryContentPacket.setContainerNameData(new FullContainerName(ContainerSlotType.ANVIL_INPUT, null));
|
||||
session.sendUpstreamPacket(inventoryContentPacket);
|
||||
|
||||
// Armor
|
||||
|
@ -99,12 +101,14 @@ public class PlayerInventoryTranslator extends InventoryTranslator {
|
|||
}
|
||||
}
|
||||
armorContentPacket.setContents(Arrays.asList(contents));
|
||||
armorContentPacket.setContainerNameData(new FullContainerName(ContainerSlotType.ANVIL_INPUT, null));
|
||||
session.sendUpstreamPacket(armorContentPacket);
|
||||
|
||||
// Offhand
|
||||
InventoryContentPacket offhandPacket = new InventoryContentPacket();
|
||||
offhandPacket.setContainerId(ContainerId.OFFHAND);
|
||||
offhandPacket.setContents(Collections.singletonList(inventory.getItem(45).getItemData(session)));
|
||||
offhandPacket.setContainerNameData(new FullContainerName(ContainerSlotType.ANVIL_INPUT, null));
|
||||
session.sendUpstreamPacket(offhandPacket);
|
||||
}
|
||||
|
||||
|
@ -126,6 +130,7 @@ public class PlayerInventoryTranslator extends InventoryTranslator {
|
|||
slotPacket.setItem(inventory.getItem(i).getItemData(session));
|
||||
}
|
||||
|
||||
slotPacket.setContainerNameData(new FullContainerName(ContainerSlotType.ANVIL_INPUT, null));
|
||||
session.sendUpstreamPacket(slotPacket);
|
||||
}
|
||||
}
|
||||
|
@ -162,11 +167,13 @@ public class PlayerInventoryTranslator extends InventoryTranslator {
|
|||
slotPacket.setSlot(slot + 27);
|
||||
}
|
||||
slotPacket.setItem(bedrockItem);
|
||||
slotPacket.setContainerNameData(new FullContainerName(ContainerSlotType.ANVIL_INPUT, null));
|
||||
session.sendUpstreamPacket(slotPacket);
|
||||
} else if (slot == 45) {
|
||||
InventoryContentPacket offhandPacket = new InventoryContentPacket();
|
||||
offhandPacket.setContainerId(ContainerId.OFFHAND);
|
||||
offhandPacket.setContents(Collections.singletonList(bedrockItem));
|
||||
offhandPacket.setContainerNameData(new FullContainerName(ContainerSlotType.ANVIL_INPUT, null));
|
||||
session.sendUpstreamPacket(offhandPacket);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -27,6 +27,7 @@ package org.geysermc.geyser.translator.inventory.horse;
|
|||
|
||||
import org.cloudburstmc.protocol.bedrock.data.inventory.ContainerId;
|
||||
import org.cloudburstmc.protocol.bedrock.data.inventory.ContainerSlotType;
|
||||
import org.cloudburstmc.protocol.bedrock.data.inventory.FullContainerName;
|
||||
import org.cloudburstmc.protocol.bedrock.data.inventory.ItemData;
|
||||
import org.cloudburstmc.protocol.bedrock.data.inventory.itemstack.request.ItemStackRequestSlotData;
|
||||
import org.cloudburstmc.protocol.bedrock.packet.InventoryContentPacket;
|
||||
|
@ -94,6 +95,7 @@ public abstract class ChestedHorseInventoryTranslator extends AbstractHorseInven
|
|||
InventoryContentPacket contentPacket = new InventoryContentPacket();
|
||||
contentPacket.setContainerId(ContainerId.INVENTORY);
|
||||
contentPacket.setContents(Arrays.asList(bedrockItems));
|
||||
contentPacket.setContainerNameData(new FullContainerName(ContainerSlotType.ANVIL_INPUT, null));
|
||||
session.sendUpstreamPacket(contentPacket);
|
||||
|
||||
ItemData[] horseItems = new ItemData[chestSize + 1];
|
||||
|
@ -107,6 +109,7 @@ public abstract class ChestedHorseInventoryTranslator extends AbstractHorseInven
|
|||
InventoryContentPacket horseContentsPacket = new InventoryContentPacket();
|
||||
horseContentsPacket.setContainerId(inventory.getBedrockId());
|
||||
horseContentsPacket.setContents(Arrays.asList(horseItems));
|
||||
horseContentsPacket.setContainerNameData(new FullContainerName(ContainerSlotType.ANVIL_INPUT, null));
|
||||
session.sendUpstreamPacket(horseContentsPacket);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -31,6 +31,7 @@ import org.cloudburstmc.math.vector.Vector3d;
|
|||
import org.cloudburstmc.math.vector.Vector3f;
|
||||
import org.cloudburstmc.math.vector.Vector3i;
|
||||
import org.cloudburstmc.protocol.bedrock.data.LevelEvent;
|
||||
import org.cloudburstmc.protocol.bedrock.data.SoundEvent;
|
||||
import org.cloudburstmc.protocol.bedrock.data.definitions.BlockDefinition;
|
||||
import org.cloudburstmc.protocol.bedrock.data.definitions.ItemDefinition;
|
||||
import org.cloudburstmc.protocol.bedrock.data.inventory.ContainerType;
|
||||
|
@ -42,6 +43,7 @@ import org.cloudburstmc.protocol.bedrock.data.inventory.transaction.LegacySetIte
|
|||
import org.cloudburstmc.protocol.bedrock.packet.ContainerOpenPacket;
|
||||
import org.cloudburstmc.protocol.bedrock.packet.InventoryTransactionPacket;
|
||||
import org.cloudburstmc.protocol.bedrock.packet.LevelEventPacket;
|
||||
import org.cloudburstmc.protocol.bedrock.packet.LevelSoundEventPacket;
|
||||
import org.cloudburstmc.protocol.bedrock.packet.UpdateBlockPacket;
|
||||
import org.geysermc.geyser.entity.EntityDefinitions;
|
||||
import org.geysermc.geyser.entity.type.Entity;
|
||||
|
@ -75,12 +77,15 @@ import org.geysermc.geyser.util.CooldownUtils;
|
|||
import org.geysermc.geyser.util.EntityUtils;
|
||||
import org.geysermc.geyser.util.InteractionResult;
|
||||
import org.geysermc.geyser.util.InventoryUtils;
|
||||
import org.geysermc.mcprotocollib.protocol.data.game.Holder;
|
||||
import org.geysermc.mcprotocollib.protocol.data.game.entity.object.Direction;
|
||||
import org.geysermc.mcprotocollib.protocol.data.game.entity.player.GameMode;
|
||||
import org.geysermc.mcprotocollib.protocol.data.game.entity.player.Hand;
|
||||
import org.geysermc.mcprotocollib.protocol.data.game.entity.player.InteractAction;
|
||||
import org.geysermc.mcprotocollib.protocol.data.game.entity.player.PlayerAction;
|
||||
import org.geysermc.mcprotocollib.protocol.data.game.item.ItemStack;
|
||||
import org.geysermc.mcprotocollib.protocol.data.game.item.component.DataComponentType;
|
||||
import org.geysermc.mcprotocollib.protocol.data.game.item.component.Instrument;
|
||||
import org.geysermc.mcprotocollib.protocol.packet.ingame.serverbound.inventory.ServerboundContainerClickPacket;
|
||||
import org.geysermc.mcprotocollib.protocol.packet.ingame.serverbound.player.ServerboundInteractPacket;
|
||||
import org.geysermc.mcprotocollib.protocol.packet.ingame.serverbound.player.ServerboundMovePlayerPosRotPacket;
|
||||
|
@ -373,6 +378,22 @@ public class BedrockInventoryTransactionTranslator extends PacketTranslator<Inve
|
|||
break;
|
||||
} else if (packet.getItemInHand().getDefinition() == session.getItemMappings().getStoredItems().writtenBook().getBedrockDefinition()) {
|
||||
session.setCurrentBook(packet.getItemInHand());
|
||||
} else if (session.getPlayerInventory().getItemInHand().asItem() == Items.GOAT_HORN) {
|
||||
// Temporary workaround while we don't have full item/block use tracking.
|
||||
if (!session.getWorldCache().hasCooldown(Items.GOAT_HORN)) {
|
||||
Holder<Instrument> instrument = session.getPlayerInventory()
|
||||
.getItemInHand()
|
||||
.getComponent(DataComponentType.INSTRUMENT);
|
||||
if (instrument != null && instrument.isId()) {
|
||||
// BDS uses a LevelSoundEvent2Packet, but that doesn't work here... (as of 1.21.20)
|
||||
LevelSoundEventPacket soundPacket = new LevelSoundEventPacket();
|
||||
soundPacket.setSound(SoundEvent.valueOf("GOAT_CALL_" + instrument.id()));
|
||||
soundPacket.setPosition(session.getPlayerEntity().getPosition());
|
||||
soundPacket.setIdentifier("minecraft:player");
|
||||
soundPacket.setExtraData(-1);
|
||||
session.sendUpstreamPacket(soundPacket);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -30,6 +30,8 @@ import org.cloudburstmc.protocol.bedrock.data.SoundEvent;
|
|||
import org.cloudburstmc.protocol.bedrock.data.entity.EntityDataTypes;
|
||||
import org.cloudburstmc.protocol.bedrock.data.entity.EntityEventType;
|
||||
import org.cloudburstmc.protocol.bedrock.data.inventory.ContainerId;
|
||||
import org.cloudburstmc.protocol.bedrock.data.inventory.ContainerSlotType;
|
||||
import org.cloudburstmc.protocol.bedrock.data.inventory.FullContainerName;
|
||||
import org.cloudburstmc.protocol.bedrock.packet.EntityEventPacket;
|
||||
import org.cloudburstmc.protocol.bedrock.packet.InventoryContentPacket;
|
||||
import org.cloudburstmc.protocol.bedrock.packet.LevelEventPacket;
|
||||
|
@ -167,6 +169,7 @@ public class JavaEntityEventTranslator extends PacketTranslator<ClientboundEntit
|
|||
InventoryContentPacket offhandPacket = new InventoryContentPacket();
|
||||
offhandPacket.setContainerId(ContainerId.OFFHAND);
|
||||
offhandPacket.setContents(Collections.singletonList(InventoryUtils.getTotemOfUndying().apply(session.getUpstream().getProtocolVersion())));
|
||||
offhandPacket.setContainerNameData(new FullContainerName(ContainerSlotType.ANVIL_INPUT, null));
|
||||
session.sendUpstreamPacket(offhandPacket);
|
||||
}
|
||||
|
||||
|
|
|
@ -25,6 +25,8 @@
|
|||
|
||||
package org.geysermc.geyser.translator.protocol.java.inventory;
|
||||
|
||||
import org.cloudburstmc.protocol.bedrock.data.inventory.ContainerSlotType;
|
||||
import org.cloudburstmc.protocol.bedrock.data.inventory.FullContainerName;
|
||||
import org.geysermc.mcprotocollib.protocol.data.game.item.ItemStack;
|
||||
import org.geysermc.mcprotocollib.protocol.data.game.recipe.Ingredient;
|
||||
import org.geysermc.mcprotocollib.protocol.packet.ingame.clientbound.inventory.ClientboundContainerSetSlotPacket;
|
||||
|
@ -180,6 +182,7 @@ public class JavaContainerSetSlotTranslator extends PacketTranslator<Clientbound
|
|||
slotPacket.setContainerId(ContainerId.UI);
|
||||
slotPacket.setSlot(col + (row * gridDimensions) + offset);
|
||||
slotPacket.setItem(ItemData.AIR);
|
||||
slotPacket.setContainerNameData(new FullContainerName(ContainerSlotType.ANVIL_INPUT, null));
|
||||
session.sendUpstreamPacket(slotPacket);
|
||||
index++;
|
||||
}
|
||||
|
@ -212,6 +215,7 @@ public class JavaContainerSetSlotTranslator extends PacketTranslator<Clientbound
|
|||
slotPacket.setContainerId(ContainerId.UI);
|
||||
slotPacket.setSlot(col + (row * gridDimensions) + offset);
|
||||
slotPacket.setItem(ingredients[index]);
|
||||
slotPacket.setContainerNameData(new FullContainerName(ContainerSlotType.ANVIL_INPUT, null));
|
||||
session.sendUpstreamPacket(slotPacket);
|
||||
index++;
|
||||
}
|
||||
|
|
|
@ -57,5 +57,7 @@ public class JavaCooldownTranslator extends PacketTranslator<ClientboundCooldown
|
|||
bedrockPacket.setCooldownDuration(packet.getCooldownTicks());
|
||||
session.sendUpstreamPacket(bedrockPacket);
|
||||
}
|
||||
|
||||
session.getWorldCache().setCooldown(item, packet.getCooldownTicks());
|
||||
}
|
||||
}
|
||||
|
|
|
@ -26,10 +26,14 @@
|
|||
package org.geysermc.geyser.translator.text;
|
||||
|
||||
import net.kyori.adventure.text.Component;
|
||||
import net.kyori.adventure.text.JoinConfiguration;
|
||||
import net.kyori.adventure.text.ScoreComponent;
|
||||
import net.kyori.adventure.text.TranslatableComponent;
|
||||
import net.kyori.adventure.text.flattener.ComponentFlattener;
|
||||
import net.kyori.adventure.text.format.NamedTextColor;
|
||||
import net.kyori.adventure.text.format.Style;
|
||||
import net.kyori.adventure.text.format.TextColor;
|
||||
import net.kyori.adventure.text.format.TextDecoration;
|
||||
import net.kyori.adventure.text.renderer.TranslatableComponentRenderer;
|
||||
import net.kyori.adventure.text.serializer.gson.GsonComponentSerializer;
|
||||
import net.kyori.adventure.text.serializer.legacy.CharacterAndFormat;
|
||||
|
@ -39,14 +43,22 @@ import org.cloudburstmc.nbt.NbtMap;
|
|||
import org.cloudburstmc.protocol.bedrock.packet.TextPacket;
|
||||
import org.geysermc.geyser.GeyserImpl;
|
||||
import org.geysermc.geyser.session.GeyserSession;
|
||||
import org.geysermc.geyser.text.*;
|
||||
import org.geysermc.geyser.text.ChatColor;
|
||||
import org.geysermc.geyser.text.ChatDecoration;
|
||||
import org.geysermc.geyser.text.DummyLegacyHoverEventSerializer;
|
||||
import org.geysermc.geyser.text.GeyserLocale;
|
||||
import org.geysermc.geyser.text.GsonComponentSerializerWrapper;
|
||||
import org.geysermc.geyser.text.MinecraftTranslationRegistry;
|
||||
import org.geysermc.mcprotocollib.protocol.data.DefaultComponentSerializer;
|
||||
import org.geysermc.mcprotocollib.protocol.data.game.Holder;
|
||||
import org.geysermc.mcprotocollib.protocol.data.game.chat.ChatType;
|
||||
import org.geysermc.mcprotocollib.protocol.data.game.chat.ChatTypeDecoration;
|
||||
import org.geysermc.mcprotocollib.protocol.data.game.scoreboard.TeamColor;
|
||||
|
||||
import java.util.*;
|
||||
import java.util.ArrayList;
|
||||
import java.util.EnumMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
public class MessageTranslator {
|
||||
// These are used for handling the translations of the messages
|
||||
|
@ -341,16 +353,16 @@ public class MessageTranslator {
|
|||
// Though, Bedrock cannot care about the signed stuff.
|
||||
TranslatableComponent.Builder withDecoration = Component.translatable()
|
||||
.key(chat.translationKey())
|
||||
.style(TextDecoration.getStyle(chat));
|
||||
.style(ChatDecoration.getStyle(chat));
|
||||
List<ChatTypeDecoration.Parameter> parameters = chat.parameters();
|
||||
List<Component> args = new ArrayList<>(3);
|
||||
if (parameters.contains(TextDecoration.Parameter.TARGET)) {
|
||||
if (parameters.contains(ChatDecoration.Parameter.TARGET)) {
|
||||
args.add(targetName);
|
||||
}
|
||||
if (parameters.contains(TextDecoration.Parameter.SENDER)) {
|
||||
if (parameters.contains(ChatDecoration.Parameter.SENDER)) {
|
||||
args.add(sender);
|
||||
}
|
||||
if (parameters.contains(TextDecoration.Parameter.CONTENT)) {
|
||||
if (parameters.contains(ChatDecoration.Parameter.CONTENT)) {
|
||||
args.add(message);
|
||||
}
|
||||
withDecoration.arguments(args);
|
||||
|
@ -426,17 +438,92 @@ public class MessageTranslator {
|
|||
}
|
||||
|
||||
/**
|
||||
* Deserialize an NbtMap provided from a registry into a string.
|
||||
* Deserialize an NbtMap with a description text component (usually provided from a registry) into a Bedrock-formatted string.
|
||||
*/
|
||||
// This may be a Component in the future.
|
||||
public static String deserializeDescription(NbtMap tag) {
|
||||
NbtMap description = tag.getCompound("description");
|
||||
String translate = description.getString("translate", null);
|
||||
if (translate == null) {
|
||||
GeyserImpl.getInstance().getLogger().debug("Don't know how to read description! " + tag);
|
||||
return "";
|
||||
public static String deserializeDescription(GeyserSession session, NbtMap tag) {
|
||||
Object description = tag.get("description");
|
||||
Component parsed = componentFromNbtTag(description);
|
||||
return convertMessage(session, parsed);
|
||||
}
|
||||
|
||||
public static Component componentFromNbtTag(Object nbtTag) {
|
||||
return componentFromNbtTag(nbtTag, Style.empty());
|
||||
}
|
||||
|
||||
private static Component componentFromNbtTag(Object nbtTag, Style style) {
|
||||
if (nbtTag instanceof String literal) {
|
||||
return Component.text(literal).style(style);
|
||||
} else if (nbtTag instanceof List<?> list) {
|
||||
return Component.join(JoinConfiguration.noSeparators(), componentsFromNbtList(list, style));
|
||||
} else if (nbtTag instanceof NbtMap map) {
|
||||
Component component = null;
|
||||
String text = map.getString("text", null);
|
||||
if (text != null) {
|
||||
component = Component.text(text);
|
||||
} else {
|
||||
String translateKey = map.getString("translate", null);
|
||||
if (translateKey != null) {
|
||||
String fallback = map.getString("fallback", "");
|
||||
List<Component> args = new ArrayList<>();
|
||||
|
||||
Object with = map.get("with");
|
||||
if (with instanceof List<?> list) {
|
||||
args = componentsFromNbtList(list, style);
|
||||
} else if (with != null) {
|
||||
args.add(componentFromNbtTag(with, style));
|
||||
}
|
||||
component = Component.translatable(translateKey, fallback, args);
|
||||
}
|
||||
}
|
||||
|
||||
if (component != null) {
|
||||
Style newStyle = getStyleFromNbtMap(map, style);
|
||||
component = component.style(newStyle);
|
||||
|
||||
Object extra = map.get("extra");
|
||||
if (extra != null) {
|
||||
component = component.append(componentFromNbtTag(extra, newStyle));
|
||||
}
|
||||
|
||||
return component;
|
||||
}
|
||||
}
|
||||
return translate;
|
||||
|
||||
GeyserImpl.getInstance().getLogger().error("Expected tag to be a literal string, a list of components, or a component object with a text/translate key: " + nbtTag);
|
||||
return Component.empty();
|
||||
}
|
||||
|
||||
private static List<Component> componentsFromNbtList(List<?> list, Style style) {
|
||||
List<Component> components = new ArrayList<>();
|
||||
for (Object entry : list) {
|
||||
components.add(componentFromNbtTag(entry, style));
|
||||
}
|
||||
return components;
|
||||
}
|
||||
|
||||
public static Style getStyleFromNbtMap(NbtMap map) {
|
||||
Style.Builder style = Style.style();
|
||||
|
||||
String colorString = map.getString("color", null);
|
||||
if (colorString != null) {
|
||||
if (colorString.startsWith(TextColor.HEX_PREFIX)) {
|
||||
style.color(TextColor.fromHexString(colorString));
|
||||
} else {
|
||||
style.color(NamedTextColor.NAMES.value(colorString));
|
||||
}
|
||||
}
|
||||
|
||||
map.listenForBoolean("bold", value -> style.decoration(TextDecoration.BOLD, value));
|
||||
map.listenForBoolean("italic", value -> style.decoration(TextDecoration.ITALIC, value));
|
||||
map.listenForBoolean("underlined", value -> style.decoration(TextDecoration.UNDERLINED, value));
|
||||
map.listenForBoolean("strikethrough", value -> style.decoration(TextDecoration.STRIKETHROUGH, value));
|
||||
map.listenForBoolean("obfuscated", value -> style.decoration(TextDecoration.OBFUSCATED, value));
|
||||
|
||||
return style.build();
|
||||
}
|
||||
|
||||
public static Style getStyleFromNbtMap(NbtMap map, Style base) {
|
||||
return base.merge(getStyleFromNbtMap(map));
|
||||
}
|
||||
|
||||
public static void init() {
|
||||
|
|
|
@ -32,6 +32,8 @@ import org.cloudburstmc.nbt.NbtMapBuilder;
|
|||
import org.cloudburstmc.nbt.NbtType;
|
||||
import org.cloudburstmc.protocol.bedrock.data.definitions.ItemDefinition;
|
||||
import org.cloudburstmc.protocol.bedrock.data.inventory.ContainerId;
|
||||
import org.cloudburstmc.protocol.bedrock.data.inventory.ContainerSlotType;
|
||||
import org.cloudburstmc.protocol.bedrock.data.inventory.FullContainerName;
|
||||
import org.cloudburstmc.protocol.bedrock.data.inventory.ItemData;
|
||||
import org.cloudburstmc.protocol.bedrock.packet.InventorySlotPacket;
|
||||
import org.cloudburstmc.protocol.bedrock.packet.PlayerHotbarPacket;
|
||||
|
@ -180,6 +182,7 @@ public class InventoryUtils {
|
|||
cursorPacket.setContainerId(ContainerId.UI);
|
||||
cursorPacket.setSlot(0);
|
||||
cursorPacket.setItem(session.getPlayerInventory().getCursor().getItemData(session));
|
||||
cursorPacket.setContainerNameData(new FullContainerName(ContainerSlotType.ANVIL_INPUT, null));
|
||||
session.sendUpstreamPacket(cursorPacket);
|
||||
}
|
||||
|
||||
|
|
BIN
core/src/main/resources/bedrock/block_palette.1_21_30.nbt
Normal file
BIN
core/src/main/resources/bedrock/block_palette.1_21_30.nbt
Normal file
Binary file not shown.
6214
core/src/main/resources/bedrock/creative_items.1_21_30.json
Normal file
6214
core/src/main/resources/bedrock/creative_items.1_21_30.json
Normal file
File diff suppressed because it is too large
Load diff
6898
core/src/main/resources/bedrock/runtime_item_states.1_21_30.json
Normal file
6898
core/src/main/resources/bedrock/runtime_item_states.1_21_30.json
Normal file
File diff suppressed because it is too large
Load diff
|
@ -1 +1 @@
|
|||
Subproject commit 698fd2b108a9e53f1e47b8cfdc122651b70d6059
|
||||
Subproject commit 93f207e7e9d73f58a7c8902f7deda9dcb0524c8e
|
|
@ -8,5 +8,5 @@ org.gradle.vfs.watch=false
|
|||
|
||||
group=org.geysermc
|
||||
id=geyser
|
||||
version=2.4.2-SNAPSHOT
|
||||
version=2.4.3-SNAPSHOT
|
||||
description=Allows for players from Minecraft: Bedrock Edition to join Minecraft: Java Edition servers.
|
||||
|
|
|
@ -13,9 +13,9 @@ guava = "29.0-jre"
|
|||
gson = "2.3.1" # Provided by Spigot 1.8.8 TODO bump to 2.8.1 or similar (Spigot 1.16.5 version) after Merge
|
||||
gson-runtime = "2.10.1"
|
||||
websocket = "1.5.1"
|
||||
protocol-connection = "3.0.0.Beta4-20240828.162251-1"
|
||||
protocol-common = "3.0.0.Beta4-20240828.162251-1"
|
||||
protocol-codec = "3.0.0.Beta4-20240828.162251-1"
|
||||
protocol-connection = "3.0.0.Beta5-20240916.181041-6"
|
||||
protocol-common = "3.0.0.Beta5-20240916.181041-6"
|
||||
protocol-codec = "3.0.0.Beta5-20240916.181041-6"
|
||||
raknet = "1.0.0.CR3-20240416.144209-1"
|
||||
minecraftauth = "4.1.1-20240806.235051-7"
|
||||
mcprotocollib = "1.21-20240725.013034-16"
|
||||
|
|
Loading…
Reference in a new issue