Mirror von
https://github.com/GeyserMC/Geyser.git
synchronisiert 2024-11-19 22:40:18 +01:00
Merge pull request #5106 from GeyserMC/feature/1.21.2
Java Edition 1.21.2 / 1.21.3 support
Dieser Commit ist enthalten in:
Commit
6983095d36
@ -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.44 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.44 and Minecraft Java 1.21.2/1.21.3. 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.
|
||||
|
@ -46,7 +46,6 @@ tasks.withType<Jar> {
|
||||
|
||||
relocate("org.cloudburstmc.netty")
|
||||
relocate("org.cloudburstmc.protocol")
|
||||
relocate("com.github.steveice10.mc.auth")
|
||||
|
||||
tasks {
|
||||
remapJar {
|
||||
|
@ -32,7 +32,7 @@ import net.fabricmc.fabric.api.event.lifecycle.v1.ServerLifecycleEvents;
|
||||
import net.fabricmc.fabric.api.networking.v1.ServerPlayConnectionEvents;
|
||||
import net.fabricmc.loader.api.FabricLoader;
|
||||
import net.minecraft.commands.CommandSourceStack;
|
||||
import net.minecraft.world.entity.player.Player;
|
||||
import net.minecraft.server.level.ServerPlayer;
|
||||
import org.geysermc.geyser.GeyserImpl;
|
||||
import org.geysermc.geyser.command.CommandRegistry;
|
||||
import org.geysermc.geyser.command.CommandSourceConverter;
|
||||
@ -80,7 +80,7 @@ public class GeyserFabricBootstrap extends GeyserModBootstrap implements ModInit
|
||||
var sourceConverter = CommandSourceConverter.layered(
|
||||
CommandSourceStack.class,
|
||||
id -> getServer().getPlayerList().getPlayer(id),
|
||||
Player::createCommandSourceStack,
|
||||
ServerPlayer::createCommandSourceStack,
|
||||
() -> getServer().createCommandSourceStack(), // NPE if method reference is used, since server is not available yet
|
||||
ModCommandSource::new
|
||||
);
|
||||
|
@ -23,8 +23,8 @@
|
||||
"geyser.mixins.json"
|
||||
],
|
||||
"depends": {
|
||||
"fabricloader": ">=0.15.11",
|
||||
"fabricloader": ">=0.16.7",
|
||||
"fabric": "*",
|
||||
"minecraft": ">=1.21"
|
||||
"minecraft": ">=1.21.2"
|
||||
}
|
||||
}
|
||||
|
@ -13,6 +13,9 @@ architectury {
|
||||
provided("org.cloudburstmc.math", "api")
|
||||
provided("com.google.errorprone", "error_prone_annotations")
|
||||
|
||||
// Jackson shipped by Minecraft is too old, so we shade & relocate our newer version
|
||||
relocate("com.fasterxml.jackson")
|
||||
|
||||
val includeTransitive: Configuration = configurations.getByName("includeTransitive")
|
||||
|
||||
dependencies {
|
||||
@ -31,6 +34,12 @@ dependencies {
|
||||
}
|
||||
shadow(projects.core) { isTransitive = false }
|
||||
|
||||
// Minecraft (1.21.2+) includes jackson. But an old version!
|
||||
shadow(libs.jackson.core) { isTransitive = false }
|
||||
shadow(libs.jackson.databind) { isTransitive = false }
|
||||
shadow(libs.jackson.dataformat.yaml) { isTransitive = false }
|
||||
shadow(libs.jackson.annotations) { isTransitive = false }
|
||||
|
||||
// Let's shade in our own api
|
||||
shadow(projects.api) { isTransitive = false }
|
||||
|
||||
@ -56,6 +65,11 @@ tasks {
|
||||
remapModrinthJar {
|
||||
archiveBaseName.set("geyser-neoforge")
|
||||
}
|
||||
|
||||
shadowJar {
|
||||
// Without this, jackson's service files are not relocated
|
||||
mergeServiceFiles()
|
||||
}
|
||||
}
|
||||
|
||||
modrinth {
|
||||
|
@ -26,7 +26,7 @@
|
||||
package org.geysermc.geyser.platform.neoforge;
|
||||
|
||||
import net.minecraft.commands.CommandSourceStack;
|
||||
import net.minecraft.world.entity.player.Player;
|
||||
import net.minecraft.server.level.ServerPlayer;
|
||||
import net.neoforged.bus.api.EventPriority;
|
||||
import net.neoforged.fml.ModContainer;
|
||||
import net.neoforged.fml.common.Mod;
|
||||
@ -72,7 +72,7 @@ public class GeyserNeoForgeBootstrap extends GeyserModBootstrap {
|
||||
var sourceConverter = CommandSourceConverter.layered(
|
||||
CommandSourceStack.class,
|
||||
id -> getServer().getPlayerList().getPlayer(id),
|
||||
Player::createCommandSourceStack,
|
||||
ServerPlayer::createCommandSourceStack,
|
||||
() -> getServer().createCommandSourceStack(),
|
||||
ModCommandSource::new
|
||||
);
|
||||
@ -104,7 +104,9 @@ public class GeyserNeoForgeBootstrap extends GeyserModBootstrap {
|
||||
}
|
||||
|
||||
private void onPlayerJoin(PlayerEvent.PlayerLoggedInEvent event) {
|
||||
GeyserModUpdateListener.onPlayReady(event.getEntity());
|
||||
if (event.getEntity() instanceof ServerPlayer player) {
|
||||
GeyserModUpdateListener.onPlayReady(player);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -28,8 +28,8 @@ package org.geysermc.geyser.platform.mod;
|
||||
import io.netty.channel.ChannelHandlerContext;
|
||||
import io.netty.channel.ChannelOutboundHandlerAdapter;
|
||||
import io.netty.channel.ChannelPromise;
|
||||
import net.minecraft.network.protocol.login.ClientboundGameProfilePacket;
|
||||
import net.minecraft.network.protocol.login.ClientboundLoginCompressionPacket;
|
||||
import net.minecraft.network.protocol.login.ClientboundLoginFinishedPacket;
|
||||
|
||||
/**
|
||||
* Disables the compression packet (and the compression handlers from being added to the pipeline) for Geyser clients
|
||||
@ -45,7 +45,7 @@ public class GeyserModCompressionDisabler extends ChannelOutboundHandlerAdapter
|
||||
Class<?> msgClass = msg.getClass();
|
||||
// Don't let any compression packet get through
|
||||
if (!ClientboundLoginCompressionPacket.class.isAssignableFrom(msgClass)) {
|
||||
if (ClientboundGameProfilePacket.class.isAssignableFrom(msgClass)) {
|
||||
if (ClientboundLoginFinishedPacket.class.isAssignableFrom(msgClass)) {
|
||||
|
||||
// We're past the point that a compression packet can be sent, so we can safely yeet ourselves away
|
||||
ctx.channel().pipeline().remove(this);
|
||||
|
@ -25,13 +25,13 @@
|
||||
|
||||
package org.geysermc.geyser.platform.mod;
|
||||
|
||||
import net.minecraft.world.entity.player.Player;
|
||||
import net.minecraft.server.level.ServerPlayer;
|
||||
import org.geysermc.geyser.Permissions;
|
||||
import org.geysermc.geyser.platform.mod.command.ModCommandSource;
|
||||
import org.geysermc.geyser.util.VersionCheckUtils;
|
||||
|
||||
public final class GeyserModUpdateListener {
|
||||
public static void onPlayReady(Player player) {
|
||||
public static void onPlayReady(ServerPlayer player) {
|
||||
// Should be creating this in the supplier, but we need it for the permission check.
|
||||
// Not a big deal currently because ModCommandSource doesn't load locale, so don't need to try to wait for it.
|
||||
ModCommandSource source = new ModCommandSource(player.createCommandSourceStack());
|
||||
|
@ -33,8 +33,10 @@ import net.minecraft.core.component.DataComponents;
|
||||
import net.minecraft.core.registries.BuiltInRegistries;
|
||||
import net.minecraft.network.chat.Component;
|
||||
import net.minecraft.server.MinecraftServer;
|
||||
import net.minecraft.server.level.ServerChunkCache;
|
||||
import net.minecraft.server.level.ServerPlayer;
|
||||
import net.minecraft.world.item.ItemStack;
|
||||
import net.minecraft.world.level.ChunkPos;
|
||||
import net.minecraft.world.level.Level;
|
||||
import net.minecraft.world.level.block.Block;
|
||||
import net.minecraft.world.level.block.entity.BannerBlockEntity;
|
||||
@ -43,7 +45,6 @@ import net.minecraft.world.level.block.entity.BlockEntity;
|
||||
import net.minecraft.world.level.block.entity.DecoratedPotBlockEntity;
|
||||
import net.minecraft.world.level.chunk.ChunkAccess;
|
||||
import net.minecraft.world.level.chunk.LevelChunkSection;
|
||||
import net.minecraft.world.level.chunk.status.ChunkStatus;
|
||||
import org.checkerframework.checker.nullness.qual.NonNull;
|
||||
import org.cloudburstmc.math.vector.Vector3i;
|
||||
import org.geysermc.geyser.level.GeyserWorldManager;
|
||||
@ -84,16 +85,17 @@ public class GeyserModWorldManager extends GeyserWorldManager {
|
||||
}
|
||||
|
||||
Level level = player.level();
|
||||
if (y < level.getMinBuildHeight()) {
|
||||
if (y < level.getMinY()) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
ChunkAccess chunk = level.getChunkSource().getChunk(x >> 4, z >> 4, ChunkStatus.FULL, false);
|
||||
// Only loads active chunks, and doesn't delegate to main thread
|
||||
ChunkAccess chunk = ((ServerChunkCache) level.getChunkSource()).chunkMap.getChunkToSend(ChunkPos.asLong(x >> 4, z >> 4));
|
||||
if (chunk == null) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
int worldOffset = level.getMinBuildHeight() >> 4;
|
||||
int worldOffset = level.getMinY() >> 4;
|
||||
int chunkOffset = (y >> 4) - worldOffset;
|
||||
if (chunkOffset < chunk.getSections().length) {
|
||||
LevelChunkSection section = chunk.getSections()[chunkOffset];
|
||||
|
@ -33,10 +33,24 @@ import org.geysermc.geyser.GeyserImpl;
|
||||
import org.geysermc.geyser.GeyserLogger;
|
||||
import org.geysermc.geyser.command.GeyserCommandSource;
|
||||
import org.geysermc.geyser.text.ChatColor;
|
||||
import org.jline.reader.Candidate;
|
||||
import org.jline.reader.LineReader;
|
||||
import org.jline.reader.LineReaderBuilder;
|
||||
|
||||
@Slf4j
|
||||
public class GeyserStandaloneLogger extends SimpleTerminalConsole implements GeyserLogger, GeyserCommandSource {
|
||||
|
||||
@Override
|
||||
protected LineReader buildReader(LineReaderBuilder builder) {
|
||||
builder.completer((reader, line, candidates) -> {
|
||||
var suggestions = GeyserImpl.getInstance().commandRegistry().suggestionsFor(this, line.line());
|
||||
for (var suggestion : suggestions.list()) {
|
||||
candidates.add(new Candidate(suggestion.suggestion()));
|
||||
}
|
||||
});
|
||||
return super.buildReader(builder);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean isRunning() {
|
||||
return !GeyserImpl.getInstance().isShuttingDown();
|
||||
|
@ -7,12 +7,13 @@ tasks.modrinth.get().dependsOn(tasks.modrinthSyncBody)
|
||||
|
||||
modrinth {
|
||||
token.set(System.getenv("MODRINTH_TOKEN") ?: "") // Even though this is the default value, apparently this prevents GitHub Actions caching the token?
|
||||
debugMode.set(System.getenv("MODRINTH_TOKEN") == null)
|
||||
projectId.set("geyser")
|
||||
versionName.set(versionName(project))
|
||||
versionNumber.set(projectVersion(project))
|
||||
versionType.set("beta")
|
||||
changelog.set(System.getenv("CHANGELOG") ?: "")
|
||||
gameVersions.addAll("1.21", libs.minecraft.get().version as String)
|
||||
gameVersions.addAll("1.21.2", libs.minecraft.get().version as String)
|
||||
failSilently.set(true)
|
||||
|
||||
syncBodyFrom.set(rootProject.file("README.md").readText())
|
||||
|
@ -27,6 +27,13 @@ package org.geysermc.geyser.command;
|
||||
|
||||
import it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap;
|
||||
import org.checkerframework.checker.nullness.qual.NonNull;
|
||||
import org.cloudburstmc.protocol.bedrock.data.command.CommandData;
|
||||
import org.cloudburstmc.protocol.bedrock.data.command.CommandEnumConstraint;
|
||||
import org.cloudburstmc.protocol.bedrock.data.command.CommandEnumData;
|
||||
import org.cloudburstmc.protocol.bedrock.data.command.CommandOverloadData;
|
||||
import org.cloudburstmc.protocol.bedrock.data.command.CommandParam;
|
||||
import org.cloudburstmc.protocol.bedrock.data.command.CommandParamData;
|
||||
import org.cloudburstmc.protocol.bedrock.data.command.CommandPermission;
|
||||
import org.geysermc.geyser.GeyserImpl;
|
||||
import org.geysermc.geyser.api.command.Command;
|
||||
import org.geysermc.geyser.api.event.EventRegistrar;
|
||||
@ -51,14 +58,29 @@ import org.geysermc.geyser.command.defaults.StopCommand;
|
||||
import org.geysermc.geyser.command.defaults.VersionCommand;
|
||||
import org.geysermc.geyser.event.type.GeyserDefineCommandsEventImpl;
|
||||
import org.geysermc.geyser.extension.command.GeyserExtensionCommand;
|
||||
import org.geysermc.geyser.session.GeyserSession;
|
||||
import org.geysermc.geyser.text.GeyserLocale;
|
||||
import org.incendo.cloud.Command.Builder;
|
||||
import org.incendo.cloud.CommandManager;
|
||||
import org.incendo.cloud.execution.ExecutionCoordinator;
|
||||
import org.incendo.cloud.internal.CommandNode;
|
||||
import org.incendo.cloud.parser.standard.EnumParser;
|
||||
import org.incendo.cloud.parser.standard.IntegerParser;
|
||||
import org.incendo.cloud.parser.standard.LiteralParser;
|
||||
import org.incendo.cloud.parser.standard.StringArrayParser;
|
||||
import org.incendo.cloud.suggestion.Suggestion;
|
||||
import org.incendo.cloud.suggestion.Suggestions;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.EnumSet;
|
||||
import java.util.HashMap;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import static org.geysermc.geyser.command.GeyserCommand.DEFAULT_ROOT_COMMAND;
|
||||
|
||||
@ -299,4 +321,90 @@ public class CommandRegistry implements EventRegistrar {
|
||||
public void runCommand(@NonNull GeyserCommandSource source, @NonNull String command) {
|
||||
cloud.commandExecutor().executeCommand(source, command);
|
||||
}
|
||||
|
||||
public Suggestions<GeyserCommandSource, ? extends Suggestion> suggestionsFor(GeyserCommandSource source, String input) {
|
||||
return cloud.suggestionFactory().suggestImmediately(source, input);
|
||||
}
|
||||
|
||||
public void export(GeyserSession session, List<CommandData> bedrockCommands, Set<String> knownAliases) {
|
||||
cloud.commandTree().rootNodes().forEach(commandTree -> {
|
||||
var command = commandTree.command();
|
||||
// Command null happens if you register an extension command with custom Cloud parameters...
|
||||
if (command == null || session.hasPermission(command.commandPermission().permissionString())) {
|
||||
var rootComponent = commandTree.component();
|
||||
String name = rootComponent.name();
|
||||
if (!knownAliases.add(name)) {
|
||||
// If the server already defined the command, let's not crash.
|
||||
return;
|
||||
}
|
||||
|
||||
LinkedHashMap<String, Set<CommandEnumConstraint>> values = new LinkedHashMap<>();
|
||||
for (String s : rootComponent.aliases()) {
|
||||
values.put(s, EnumSet.of(CommandEnumConstraint.ALLOW_ALIASES));
|
||||
}
|
||||
CommandEnumData aliases = new CommandEnumData(name + "Aliases", values, false);
|
||||
|
||||
List<CommandOverloadData> data = new ArrayList<>();
|
||||
for (var node : commandTree.children()) {
|
||||
List<List<CommandParamData>> params = createParamData(session, node);
|
||||
params.forEach(param -> data.add(new CommandOverloadData(false, param.toArray(CommandParamData[]::new))));
|
||||
}
|
||||
|
||||
CommandData bedrockCommand = new CommandData(name, rootComponent.description().textDescription(),
|
||||
Set.of(CommandData.Flag.NOT_CHEAT), CommandPermission.ANY, aliases,
|
||||
Collections.emptyList(), data.toArray(new CommandOverloadData[0]));
|
||||
bedrockCommands.add(bedrockCommand);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private List<List<CommandParamData>> createParamData(GeyserSession session, CommandNode<GeyserCommandSource> node) {
|
||||
var command = node.command();
|
||||
if (command != null && !session.hasPermission(command.commandPermission().permissionString())) {
|
||||
// Triggers with subcommands like Geyser dump, stop, etc.
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
CommandParamData data = new CommandParamData();
|
||||
var component = node.component();
|
||||
data.setName(component.name());
|
||||
data.setOptional(component.optional());
|
||||
var suggestionProvider = component.suggestionProvider();
|
||||
if (suggestionProvider instanceof LiteralParser<GeyserCommandSource> parser) {
|
||||
Map<String, Set<CommandEnumConstraint>> values = new LinkedHashMap<>();
|
||||
for (String alias : parser.aliases()) {
|
||||
values.put(alias, Set.of());
|
||||
}
|
||||
|
||||
data.setEnumData(new CommandEnumData(component.name(), values, false));
|
||||
} else if (suggestionProvider instanceof IntegerParser<GeyserCommandSource>) {
|
||||
data.setType(CommandParam.INT);
|
||||
} else if (suggestionProvider instanceof EnumParser<?,?> parser) {
|
||||
LinkedHashMap<String, Set<CommandEnumConstraint>> map = new LinkedHashMap<>();
|
||||
for (Enum<?> e : parser.acceptedValues()) {
|
||||
map.put(e.name().toLowerCase(Locale.ROOT), Set.of());
|
||||
}
|
||||
|
||||
data.setEnumData(new CommandEnumData(component.name().toLowerCase(Locale.ROOT), map, false));
|
||||
} else if (component.parser() instanceof StringArrayParser<?>) {
|
||||
data.setType(CommandParam.TEXT);
|
||||
} else {
|
||||
data.setType(CommandParam.STRING);
|
||||
}
|
||||
|
||||
var children = node.children();
|
||||
if (children.isEmpty()) {
|
||||
List<CommandParamData> list = new ArrayList<>(); // Must be mutable; parents will be added to list.
|
||||
list.add(data);
|
||||
return Collections.singletonList(list); // Safe to do; will be consumed in an addAll call.
|
||||
}
|
||||
List<List<CommandParamData>> collectiveData = new ArrayList<>();
|
||||
// If a node has multiple children, this will need to be represented
|
||||
// by creating a new list/branch for each and cloning this node down each line.
|
||||
for (var child : children) {
|
||||
collectiveData.addAll(createParamData(session, child));
|
||||
}
|
||||
collectiveData.forEach(list -> list.add(0, data));
|
||||
return collectiveData;
|
||||
}
|
||||
}
|
||||
|
@ -151,29 +151,37 @@ import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.type.FloatE
|
||||
import org.geysermc.mcprotocollib.protocol.data.game.entity.type.EntityType;
|
||||
|
||||
public final class EntityDefinitions {
|
||||
public static final EntityDefinition<BoatEntity> ACACIA_BOAT;
|
||||
public static final EntityDefinition<ChestBoatEntity> ACACIA_CHEST_BOAT;
|
||||
public static final EntityDefinition<AllayEntity> ALLAY;
|
||||
public static final EntityDefinition<AreaEffectCloudEntity> AREA_EFFECT_CLOUD;
|
||||
public static final EntityDefinition<ArmadilloEntity> ARMADILLO;
|
||||
public static final EntityDefinition<ArmorStandEntity> ARMOR_STAND;
|
||||
public static final EntityDefinition<ArrowEntity> ARROW;
|
||||
public static final EntityDefinition<AxolotlEntity> AXOLOTL;
|
||||
public static final EntityDefinition<BoatEntity> BAMBOO_RAFT;
|
||||
public static final EntityDefinition<ChestBoatEntity> BAMBOO_CHEST_RAFT;
|
||||
public static final EntityDefinition<BatEntity> BAT;
|
||||
public static final EntityDefinition<BeeEntity> BEE;
|
||||
public static final EntityDefinition<BoatEntity> BIRCH_BOAT;
|
||||
public static final EntityDefinition<ChestBoatEntity> BIRCH_CHEST_BOAT;
|
||||
public static final EntityDefinition<BlazeEntity> BLAZE;
|
||||
public static final EntityDefinition<BoatEntity> BOAT;
|
||||
public static final EntityDefinition<BoggedEntity> BOGGED;
|
||||
public static final EntityDefinition<BreezeEntity> BREEZE;
|
||||
public static final EntityDefinition<AbstractWindChargeEntity> BREEZE_WIND_CHARGE;
|
||||
public static final EntityDefinition<CamelEntity> CAMEL;
|
||||
public static final EntityDefinition<CatEntity> CAT;
|
||||
public static final EntityDefinition<SpiderEntity> CAVE_SPIDER;
|
||||
public static final EntityDefinition<BoatEntity> CHERRY_BOAT;
|
||||
public static final EntityDefinition<ChestBoatEntity> CHERRY_CHEST_BOAT;
|
||||
public static final EntityDefinition<MinecartEntity> CHEST_MINECART;
|
||||
public static final EntityDefinition<ChickenEntity> CHICKEN;
|
||||
public static final EntityDefinition<ChestBoatEntity> CHEST_BOAT;
|
||||
public static final EntityDefinition<AbstractFishEntity> COD;
|
||||
public static final EntityDefinition<CommandBlockMinecartEntity> COMMAND_BLOCK_MINECART;
|
||||
public static final EntityDefinition<CowEntity> COW;
|
||||
public static final EntityDefinition<CreeperEntity> CREEPER;
|
||||
public static final EntityDefinition<BoatEntity> DARK_OAK_BOAT;
|
||||
public static final EntityDefinition<ChestBoatEntity> DARK_OAK_CHEST_BOAT;
|
||||
public static final EntityDefinition<DolphinEntity> DOLPHIN;
|
||||
public static final EntityDefinition<ChestedHorseEntity> DONKEY;
|
||||
public static final EntityDefinition<FireballEntity> DRAGON_FIREBALL;
|
||||
@ -212,14 +220,20 @@ public final class EntityDefinitions {
|
||||
public static final EntityDefinition<IronGolemEntity> IRON_GOLEM;
|
||||
public static final EntityDefinition<ItemEntity> ITEM;
|
||||
public static final EntityDefinition<ItemFrameEntity> ITEM_FRAME;
|
||||
public static final EntityDefinition<BoatEntity> JUNGLE_BOAT;
|
||||
public static final EntityDefinition<ChestBoatEntity> JUNGLE_CHEST_BOAT;
|
||||
public static final EntityDefinition<LeashKnotEntity> LEASH_KNOT;
|
||||
public static final EntityDefinition<LightningEntity> LIGHTNING_BOLT;
|
||||
public static final EntityDefinition<LlamaEntity> LLAMA;
|
||||
public static final EntityDefinition<ThrowableEntity> LLAMA_SPIT;
|
||||
public static final EntityDefinition<MagmaCubeEntity> MAGMA_CUBE;
|
||||
public static final EntityDefinition<BoatEntity> MANGROVE_BOAT;
|
||||
public static final EntityDefinition<ChestBoatEntity> MANGROVE_CHEST_BOAT;
|
||||
public static final EntityDefinition<MinecartEntity> MINECART;
|
||||
public static final EntityDefinition<MooshroomEntity> MOOSHROOM;
|
||||
public static final EntityDefinition<ChestedHorseEntity> MULE;
|
||||
public static final EntityDefinition<BoatEntity> OAK_BOAT;
|
||||
public static final EntityDefinition<ChestBoatEntity> OAK_CHEST_BOAT;
|
||||
public static final EntityDefinition<OcelotEntity> OCELOT;
|
||||
public static final EntityDefinition<PaintingEntity> PAINTING;
|
||||
public static final EntityDefinition<PandaEntity> PANDA;
|
||||
@ -250,6 +264,8 @@ public final class EntityDefinitions {
|
||||
public static final EntityDefinition<SpawnerMinecartEntity> SPAWNER_MINECART; // Not present on Bedrock
|
||||
public static final EntityDefinition<AbstractArrowEntity> SPECTRAL_ARROW;
|
||||
public static final EntityDefinition<SpiderEntity> SPIDER;
|
||||
public static final EntityDefinition<BoatEntity> SPRUCE_BOAT;
|
||||
public static final EntityDefinition<ChestBoatEntity> SPRUCE_CHEST_BOAT;
|
||||
public static final EntityDefinition<SquidEntity> SQUID;
|
||||
public static final EntityDefinition<AbstractSkeletonEntity> STRAY;
|
||||
public static final EntityDefinition<StriderEntity> STRIDER;
|
||||
@ -308,23 +324,6 @@ public final class EntityDefinitions {
|
||||
.addTranslator(null) // Waiting
|
||||
.addTranslator(MetadataType.PARTICLE, AreaEffectCloudEntity::setParticle)
|
||||
.build();
|
||||
BOAT = EntityDefinition.inherited(BoatEntity::new, entityBase)
|
||||
.type(EntityType.BOAT)
|
||||
.height(0.6f).width(1.6f)
|
||||
.offset(0.35f)
|
||||
.addTranslator(MetadataType.INT, (boatEntity, entityMetadata) -> boatEntity.getDirtyMetadata().put(EntityDataTypes.HURT_TICKS, entityMetadata.getValue())) // Time since last hit
|
||||
.addTranslator(MetadataType.INT, (boatEntity, entityMetadata) -> boatEntity.getDirtyMetadata().put(EntityDataTypes.HURT_DIRECTION, entityMetadata.getValue())) // Rocking direction
|
||||
.addTranslator(MetadataType.FLOAT, (boatEntity, entityMetadata) ->
|
||||
// 'Health' in Bedrock, damage taken in Java - it makes motion in Bedrock
|
||||
boatEntity.getDirtyMetadata().put(EntityDataTypes.STRUCTURAL_INTEGRITY, 40 - ((int) ((FloatEntityMetadata) entityMetadata).getPrimitiveValue())))
|
||||
.addTranslator(MetadataType.INT, BoatEntity::setVariant)
|
||||
.addTranslator(MetadataType.BOOLEAN, BoatEntity::setPaddlingLeft)
|
||||
.addTranslator(MetadataType.BOOLEAN, BoatEntity::setPaddlingRight)
|
||||
.addTranslator(MetadataType.INT, (boatEntity, entityMetadata) -> boatEntity.getDirtyMetadata().put(EntityDataTypes.BOAT_BUBBLE_TIME, entityMetadata.getValue())) // May not actually do anything
|
||||
.build();
|
||||
CHEST_BOAT = EntityDefinition.inherited(ChestBoatEntity::new, BOAT)
|
||||
.type(EntityType.CHEST_BOAT)
|
||||
.build();
|
||||
DRAGON_FIREBALL = EntityDefinition.inherited(FireballEntity::new, entityBase)
|
||||
.type(EntityType.DRAGON_FIREBALL)
|
||||
.heightAndWidth(1.0f)
|
||||
@ -567,6 +566,45 @@ public final class EntityDefinitions {
|
||||
.build(false);
|
||||
}
|
||||
|
||||
// Boats
|
||||
{
|
||||
EntityDefinition<BoatEntity> boatBase = EntityDefinition.<BoatEntity>inherited(null, entityBase)
|
||||
.height(0.6f).width(1.6f)
|
||||
.offset(0.35f)
|
||||
.addTranslator(MetadataType.INT, (boatEntity, entityMetadata) -> boatEntity.getDirtyMetadata().put(EntityDataTypes.HURT_TICKS, entityMetadata.getValue())) // Time since last hit
|
||||
.addTranslator(MetadataType.INT, (boatEntity, entityMetadata) -> boatEntity.getDirtyMetadata().put(EntityDataTypes.HURT_DIRECTION, entityMetadata.getValue())) // Rocking direction
|
||||
.addTranslator(MetadataType.FLOAT, (boatEntity, entityMetadata) ->
|
||||
// 'Health' in Bedrock, damage taken in Java - it makes motion in Bedrock
|
||||
boatEntity.getDirtyMetadata().put(EntityDataTypes.STRUCTURAL_INTEGRITY, 40 - ((int) ((FloatEntityMetadata) entityMetadata).getPrimitiveValue())))
|
||||
.addTranslator(MetadataType.BOOLEAN, BoatEntity::setPaddlingLeft)
|
||||
.addTranslator(MetadataType.BOOLEAN, BoatEntity::setPaddlingRight)
|
||||
.addTranslator(MetadataType.INT, (boatEntity, entityMetadata) -> boatEntity.getDirtyMetadata().put(EntityDataTypes.BOAT_BUBBLE_TIME, entityMetadata.getValue())) // May not actually do anything
|
||||
.build();
|
||||
|
||||
ACACIA_BOAT = buildBoat(boatBase, EntityType.ACACIA_BOAT, BoatEntity.BoatVariant.ACACIA);
|
||||
BAMBOO_RAFT = buildBoat(boatBase, EntityType.BAMBOO_RAFT, BoatEntity.BoatVariant.BAMBOO);
|
||||
BIRCH_BOAT = buildBoat(boatBase, EntityType.BIRCH_BOAT, BoatEntity.BoatVariant.BIRCH);
|
||||
CHERRY_BOAT = buildBoat(boatBase, EntityType.CHERRY_BOAT, BoatEntity.BoatVariant.CHERRY);
|
||||
DARK_OAK_BOAT = buildBoat(boatBase, EntityType.DARK_OAK_BOAT, BoatEntity.BoatVariant.DARK_OAK);
|
||||
JUNGLE_BOAT = buildBoat(boatBase, EntityType.JUNGLE_BOAT, BoatEntity.BoatVariant.JUNGLE);
|
||||
MANGROVE_BOAT = buildBoat(boatBase, EntityType.MANGROVE_BOAT, BoatEntity.BoatVariant.MANGROVE);
|
||||
OAK_BOAT = buildBoat(boatBase, EntityType.OAK_BOAT, BoatEntity.BoatVariant.OAK);
|
||||
SPRUCE_BOAT = buildBoat(boatBase, EntityType.SPRUCE_BOAT, BoatEntity.BoatVariant.SPRUCE);
|
||||
|
||||
EntityDefinition<ChestBoatEntity> chestBoatBase = EntityDefinition.<ChestBoatEntity>inherited(null, boatBase)
|
||||
.build();
|
||||
|
||||
ACACIA_CHEST_BOAT = buildChestBoat(chestBoatBase, EntityType.ACACIA_CHEST_BOAT, BoatEntity.BoatVariant.ACACIA);
|
||||
BAMBOO_CHEST_RAFT = buildChestBoat(chestBoatBase, EntityType.BAMBOO_CHEST_RAFT, BoatEntity.BoatVariant.BAMBOO);
|
||||
BIRCH_CHEST_BOAT = buildChestBoat(chestBoatBase, EntityType.BIRCH_CHEST_BOAT, BoatEntity.BoatVariant.BIRCH);
|
||||
CHERRY_CHEST_BOAT = buildChestBoat(chestBoatBase, EntityType.CHERRY_CHEST_BOAT, BoatEntity.BoatVariant.CHERRY);
|
||||
DARK_OAK_CHEST_BOAT = buildChestBoat(chestBoatBase, EntityType.DARK_OAK_CHEST_BOAT, BoatEntity.BoatVariant.DARK_OAK);
|
||||
JUNGLE_CHEST_BOAT = buildChestBoat(chestBoatBase, EntityType.JUNGLE_CHEST_BOAT, BoatEntity.BoatVariant.JUNGLE);
|
||||
MANGROVE_CHEST_BOAT = buildChestBoat(chestBoatBase, EntityType.MANGROVE_CHEST_BOAT, BoatEntity.BoatVariant.MANGROVE);
|
||||
OAK_CHEST_BOAT = buildChestBoat(chestBoatBase, EntityType.OAK_CHEST_BOAT, BoatEntity.BoatVariant.OAK);
|
||||
SPRUCE_CHEST_BOAT = buildChestBoat(chestBoatBase, EntityType.SPRUCE_CHEST_BOAT, BoatEntity.BoatVariant.SPRUCE);
|
||||
}
|
||||
|
||||
EntityDefinition<LivingEntity> livingEntityBase = EntityDefinition.inherited(LivingEntity::new, entityBase)
|
||||
.addTranslator(MetadataType.BYTE, LivingEntity::setLivingEntityFlags)
|
||||
.addTranslator(MetadataType.FLOAT, LivingEntity::setHealth)
|
||||
@ -640,14 +678,6 @@ public final class EntityDefinitions {
|
||||
.addTranslator(MetadataType.BOOLEAN, (entity, entityMetadata) -> entity.setFlag(EntityFlag.POWERED, ((BooleanEntityMetadata) entityMetadata).getPrimitiveValue()))
|
||||
.addTranslator(MetadataType.BOOLEAN, CreeperEntity::setIgnited)
|
||||
.build();
|
||||
DOLPHIN = EntityDefinition.inherited(DolphinEntity::new, mobEntityBase)
|
||||
.type(EntityType.DOLPHIN)
|
||||
.height(0.6f).width(0.9f)
|
||||
//TODO check
|
||||
.addTranslator(null) // treasure position
|
||||
.addTranslator(null) // "got fish"
|
||||
.addTranslator(null) // "moistness level"
|
||||
.build();
|
||||
ENDERMAN = EntityDefinition.inherited(EndermanEntity::new, mobEntityBase)
|
||||
.type(EntityType.ENDERMAN)
|
||||
.height(2.9f).width(0.6f)
|
||||
@ -717,10 +747,6 @@ public final class EntityDefinitions {
|
||||
.type(EntityType.CAVE_SPIDER)
|
||||
.height(0.5f).width(0.7f)
|
||||
.build();
|
||||
SQUID = EntityDefinition.inherited(SquidEntity::new, mobEntityBase)
|
||||
.type(EntityType.SQUID)
|
||||
.heightAndWidth(0.8f)
|
||||
.build();
|
||||
STRAY = EntityDefinition.inherited(AbstractSkeletonEntity::new, mobEntityBase)
|
||||
.type(EntityType.STRAY)
|
||||
.height(1.8f).width(0.6f)
|
||||
@ -819,6 +845,7 @@ public final class EntityDefinitions {
|
||||
SALMON = EntityDefinition.inherited(abstractFishEntityBase.factory(), abstractFishEntityBase)
|
||||
.type(EntityType.SALMON)
|
||||
.height(0.5f).width(0.7f)
|
||||
.addTranslator(null) // Scale/variant - TODO
|
||||
.build();
|
||||
TADPOLE = EntityDefinition.inherited(TadpoleEntity::new, abstractFishEntityBase)
|
||||
.type(EntityType.TADPOLE)
|
||||
@ -846,11 +873,6 @@ public final class EntityDefinitions {
|
||||
.height(1.95f).width(0.6f)
|
||||
.build();
|
||||
|
||||
GLOW_SQUID = EntityDefinition.inherited(GlowSquidEntity::new, SQUID)
|
||||
.type(EntityType.GLOW_SQUID)
|
||||
.addTranslator(null) // Set dark ticks remaining, possible TODO
|
||||
.build();
|
||||
|
||||
EntityDefinition<RaidParticipantEntity> raidParticipantEntityBase = EntityDefinition.inherited(RaidParticipantEntity::new, mobEntityBase)
|
||||
.addTranslator(null) // Celebrating //TODO
|
||||
.build();
|
||||
@ -1042,6 +1064,26 @@ public final class EntityDefinitions {
|
||||
.build();
|
||||
}
|
||||
|
||||
// Water creatures (AgeableWaterCreature)
|
||||
{
|
||||
DOLPHIN = EntityDefinition.inherited(DolphinEntity::new, ageableEntityBase)
|
||||
.type(EntityType.DOLPHIN)
|
||||
.height(0.6f).width(0.9f)
|
||||
//TODO check
|
||||
.addTranslator(null) // treasure position
|
||||
.addTranslator(null) // "got fish"
|
||||
.addTranslator(null) // "moistness level"
|
||||
.build();
|
||||
SQUID = EntityDefinition.inherited(SquidEntity::new, ageableEntityBase)
|
||||
.type(EntityType.SQUID)
|
||||
.heightAndWidth(0.8f)
|
||||
.build();
|
||||
GLOW_SQUID = EntityDefinition.inherited(GlowSquidEntity::new, SQUID)
|
||||
.type(EntityType.GLOW_SQUID)
|
||||
.addTranslator(null) // Set dark ticks remaining, possible TODO
|
||||
.build();
|
||||
}
|
||||
|
||||
// Horses
|
||||
{
|
||||
EntityDefinition<AbstractHorseEntity> abstractHorseEntityBase = EntityDefinition.inherited(AbstractHorseEntity::new, ageableEntityBase)
|
||||
@ -1124,6 +1166,22 @@ public final class EntityDefinitions {
|
||||
Registries.JAVA_ENTITY_IDENTIFIERS.get().put("minecraft:marker", null); // We don't need an entity definition for this as it is never sent over the network
|
||||
}
|
||||
|
||||
private static EntityDefinition<BoatEntity> buildBoat(EntityDefinition<BoatEntity> base, EntityType entityType, BoatEntity.BoatVariant variant) {
|
||||
return EntityDefinition.inherited((session, javaId, bedrockId, uuid, definition, position, motion, yaw, pitch, headYaw) ->
|
||||
new BoatEntity(session, javaId, bedrockId, uuid, definition, position, motion, yaw, variant), base)
|
||||
.type(entityType)
|
||||
.identifier("minecraft:boat")
|
||||
.build();
|
||||
}
|
||||
|
||||
private static EntityDefinition<ChestBoatEntity> buildChestBoat(EntityDefinition<ChestBoatEntity> base, EntityType entityType, BoatEntity.BoatVariant variant) {
|
||||
return EntityDefinition.inherited((session, javaId, bedrockId, uuid, definition, position, motion, yaw, pitch, headYaw) ->
|
||||
new ChestBoatEntity(session, javaId, bedrockId, uuid, definition, position, motion, yaw, variant), base)
|
||||
.type(entityType)
|
||||
.identifier("minecraft:chest_boat")
|
||||
.build();
|
||||
}
|
||||
|
||||
public static void init() {
|
||||
// no-op
|
||||
}
|
||||
|
@ -32,12 +32,14 @@ import org.cloudburstmc.protocol.bedrock.packet.AnimatePacket;
|
||||
import org.cloudburstmc.protocol.bedrock.packet.MoveEntityAbsolutePacket;
|
||||
import org.geysermc.geyser.entity.EntityDefinition;
|
||||
import org.geysermc.geyser.entity.EntityDefinitions;
|
||||
import org.geysermc.geyser.item.Items;
|
||||
import org.geysermc.geyser.item.type.Item;
|
||||
import org.geysermc.geyser.session.GeyserSession;
|
||||
import org.geysermc.geyser.util.InteractionResult;
|
||||
import org.geysermc.geyser.util.InteractiveTag;
|
||||
import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.type.BooleanEntityMetadata;
|
||||
import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.type.IntEntityMetadata;
|
||||
import org.geysermc.mcprotocollib.protocol.data.game.entity.player.Hand;
|
||||
import org.geysermc.mcprotocollib.protocol.packet.ingame.serverbound.level.ServerboundPaddleBoatPacket;
|
||||
|
||||
import java.util.UUID;
|
||||
|
||||
@ -63,16 +65,19 @@ public class BoatEntity extends Entity implements Leashable, Tickable {
|
||||
* Saved for using the "pick" functionality on a boat.
|
||||
*/
|
||||
@Getter
|
||||
private int variant;
|
||||
protected final BoatVariant variant;
|
||||
|
||||
private long leashHolderBedrockId = -1;
|
||||
|
||||
// Looks too fast and too choppy with 0.1f, which is how I believe the Microsoftian client handles it
|
||||
private final float ROWING_SPEED = 0.1f;
|
||||
|
||||
public BoatEntity(GeyserSession session, int entityId, long geyserId, UUID uuid, EntityDefinition<?> definition, Vector3f position, Vector3f motion, float yaw, float pitch, float headYaw) {
|
||||
public BoatEntity(GeyserSession session, int entityId, long geyserId, UUID uuid, EntityDefinition<?> definition, Vector3f position, Vector3f motion, float yaw, BoatVariant variant) {
|
||||
// Initial rotation is incorrect
|
||||
super(session, entityId, geyserId, uuid, definition, position.add(0d, definition.offset(), 0d), motion, yaw + 90, 0, yaw + 90);
|
||||
this.variant = variant;
|
||||
|
||||
dirtyMetadata.put(EntityDataTypes.VARIANT, variant.ordinal());
|
||||
|
||||
// Required to be able to move on land 1.16.200+ or apply gravity not in the water 1.16.100+
|
||||
dirtyMetadata.put(EntityDataTypes.IS_BUOYANT, true);
|
||||
@ -124,15 +129,6 @@ public class BoatEntity extends Entity implements Leashable, Tickable {
|
||||
moveRelative(0, 0, 0, yaw + 90, 0, 0, isOnGround);
|
||||
}
|
||||
|
||||
public void setVariant(IntEntityMetadata entityMetadata) {
|
||||
variant = entityMetadata.getPrimitiveValue();
|
||||
dirtyMetadata.put(EntityDataTypes.VARIANT, switch (variant) {
|
||||
case 6, 7, 8 -> variant - 1; // dark_oak, mangrove, bamboo
|
||||
case 5 -> 8; // cherry
|
||||
default -> variant;
|
||||
});
|
||||
}
|
||||
|
||||
public void setPaddlingLeft(BooleanEntityMetadata entityMetadata) {
|
||||
isPaddlingLeft = entityMetadata.getPrimitiveValue();
|
||||
if (!isPaddlingLeft) {
|
||||
@ -187,6 +183,12 @@ public class BoatEntity extends Entity implements Leashable, Tickable {
|
||||
@Override
|
||||
public void tick() {
|
||||
// Java sends simply "true" and "false" (is_paddling_left), Bedrock keeps sending packets as you're rowing
|
||||
if (session.getPlayerEntity().getVehicle() == this) {
|
||||
// For packet timing accuracy, we'll send the packets here, as that's what Java Edition 1.21.3 does.
|
||||
ServerboundPaddleBoatPacket steerPacket = new ServerboundPaddleBoatPacket(session.isSteeringLeft(), session.isSteeringRight());
|
||||
session.sendDownstreamGamePacket(steerPacket);
|
||||
return;
|
||||
}
|
||||
doTick = !doTick; // Run every 100 ms
|
||||
if (!doTick || passengers.isEmpty()) {
|
||||
return;
|
||||
@ -212,6 +214,10 @@ public class BoatEntity extends Entity implements Leashable, Tickable {
|
||||
return leashHolderBedrockId;
|
||||
}
|
||||
|
||||
public Item getPickItem() {
|
||||
return variant.pickItem;
|
||||
}
|
||||
|
||||
private void sendAnimationPacket(GeyserSession session, Entity rower, AnimatePacket.Action action, float rowTime) {
|
||||
AnimatePacket packet = new AnimatePacket();
|
||||
packet.setRuntimeEntityId(rower.getGeyserId());
|
||||
@ -219,4 +225,27 @@ public class BoatEntity extends Entity implements Leashable, Tickable {
|
||||
packet.setRowingTime(rowTime);
|
||||
session.sendUpstreamPacket(packet);
|
||||
}
|
||||
|
||||
/**
|
||||
* Ordered by Bedrock ordinal
|
||||
*/
|
||||
public enum BoatVariant {
|
||||
OAK(Items.OAK_BOAT, Items.OAK_CHEST_BOAT),
|
||||
SPRUCE(Items.SPRUCE_BOAT, Items.SPRUCE_CHEST_BOAT),
|
||||
BIRCH(Items.BIRCH_BOAT, Items.BIRCH_CHEST_BOAT),
|
||||
JUNGLE(Items.JUNGLE_BOAT, Items.JUNGLE_CHEST_BOAT),
|
||||
ACACIA(Items.ACACIA_BOAT, Items.ACACIA_CHEST_BOAT),
|
||||
DARK_OAK(Items.DARK_OAK_BOAT, Items.DARK_OAK_CHEST_BOAT),
|
||||
MANGROVE(Items.MANGROVE_BOAT, Items.MANGROVE_CHEST_BOAT),
|
||||
BAMBOO(Items.BAMBOO_RAFT, Items.BAMBOO_CHEST_RAFT),
|
||||
CHERRY(Items.CHERRY_BOAT, Items.CHERRY_CHEST_BOAT);
|
||||
|
||||
private final Item pickItem;
|
||||
final Item chestPickItem;
|
||||
|
||||
BoatVariant(Item pickItem, Item chestPickItem) {
|
||||
this.pickItem = pickItem;
|
||||
this.chestPickItem = chestPickItem;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -27,6 +27,7 @@ package org.geysermc.geyser.entity.type;
|
||||
|
||||
import org.cloudburstmc.math.vector.Vector3f;
|
||||
import org.geysermc.geyser.entity.EntityDefinition;
|
||||
import org.geysermc.geyser.item.type.Item;
|
||||
import org.geysermc.geyser.session.GeyserSession;
|
||||
import org.geysermc.geyser.util.InteractionResult;
|
||||
import org.geysermc.geyser.util.InteractiveTag;
|
||||
@ -35,8 +36,8 @@ import org.geysermc.mcprotocollib.protocol.data.game.entity.player.Hand;
|
||||
import java.util.UUID;
|
||||
|
||||
public class ChestBoatEntity extends BoatEntity {
|
||||
public ChestBoatEntity(GeyserSession session, int entityId, long geyserId, UUID uuid, EntityDefinition<?> definition, Vector3f position, Vector3f motion, float yaw, float pitch, float headYaw) {
|
||||
super(session, entityId, geyserId, uuid, definition, position, motion, yaw, pitch, headYaw);
|
||||
public ChestBoatEntity(GeyserSession session, int entityId, long geyserId, UUID uuid, EntityDefinition<?> definition, Vector3f position, Vector3f motion, float yaw, BoatVariant variant) {
|
||||
super(session, entityId, geyserId, uuid, definition, position, motion, yaw, variant);
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -48,4 +49,9 @@ public class ChestBoatEntity extends BoatEntity {
|
||||
public InteractionResult interact(Hand hand) {
|
||||
return passengers.isEmpty() && !session.isSneaking() ? super.interact(hand) : InteractionResult.SUCCESS;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Item getPickItem() {
|
||||
return this.variant.chestPickItem;
|
||||
}
|
||||
}
|
||||
|
@ -25,12 +25,6 @@
|
||||
|
||||
package org.geysermc.geyser.entity.type;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.EnumSet;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
import java.util.Optional;
|
||||
import java.util.UUID;
|
||||
import lombok.AccessLevel;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
@ -67,6 +61,13 @@ import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.type.IntEnt
|
||||
import org.geysermc.mcprotocollib.protocol.data.game.entity.player.Hand;
|
||||
import org.geysermc.mcprotocollib.protocol.data.game.entity.type.EntityType;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.EnumSet;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
import java.util.Optional;
|
||||
import java.util.UUID;
|
||||
|
||||
@Getter
|
||||
@Setter
|
||||
public class Entity implements GeyserEntity {
|
||||
@ -89,6 +90,7 @@ public class Entity implements GeyserEntity {
|
||||
|
||||
/**
|
||||
* x = Yaw, y = Pitch, z = HeadYaw
|
||||
* Java: Y = Yaw, X = Pitch
|
||||
*/
|
||||
protected float yaw;
|
||||
protected float pitch;
|
||||
@ -699,9 +701,4 @@ public class Entity implements GeyserEntity {
|
||||
packet.setData(data);
|
||||
session.sendUpstreamPacket(packet);
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public <I extends Entity> @Nullable I as(Class<I> entityClass) {
|
||||
return entityClass.isInstance(this) ? (I) this : null;
|
||||
}
|
||||
}
|
||||
|
@ -25,11 +25,6 @@
|
||||
|
||||
package org.geysermc.geyser.entity.type;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
import java.util.UUID;
|
||||
import lombok.AccessLevel;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
@ -71,6 +66,12 @@ import org.geysermc.mcprotocollib.protocol.data.game.level.particle.EntityEffect
|
||||
import org.geysermc.mcprotocollib.protocol.data.game.level.particle.Particle;
|
||||
import org.geysermc.mcprotocollib.protocol.data.game.level.particle.ParticleType;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
import java.util.UUID;
|
||||
|
||||
@Getter
|
||||
@Setter
|
||||
public class LivingEntity extends Entity {
|
||||
@ -445,35 +446,35 @@ public class LivingEntity extends Entity {
|
||||
protected void updateAttribute(Attribute javaAttribute, List<AttributeData> newAttributes) {
|
||||
if (javaAttribute.getType() instanceof AttributeType.Builtin type) {
|
||||
switch (type) {
|
||||
case GENERIC_MAX_HEALTH -> {
|
||||
case MAX_HEALTH -> {
|
||||
// Since 1.18.0, setting the max health to 0 or below causes the entity to die on Bedrock but not on Java
|
||||
// See https://github.com/GeyserMC/Geyser/issues/2971
|
||||
this.maxHealth = Math.max((float) AttributeUtils.calculateValue(javaAttribute), 1f);
|
||||
newAttributes.add(createHealthAttribute());
|
||||
}
|
||||
case GENERIC_MOVEMENT_SPEED -> {
|
||||
case MOVEMENT_SPEED -> {
|
||||
AttributeData attributeData = calculateAttribute(javaAttribute, GeyserAttributeType.MOVEMENT_SPEED);
|
||||
newAttributes.add(attributeData);
|
||||
if (this instanceof ClientVehicle clientVehicle) {
|
||||
clientVehicle.getVehicleComponent().setMoveSpeed(attributeData.getValue());
|
||||
}
|
||||
}
|
||||
case GENERIC_STEP_HEIGHT -> {
|
||||
case STEP_HEIGHT -> {
|
||||
if (this instanceof ClientVehicle clientVehicle) {
|
||||
clientVehicle.getVehicleComponent().setStepHeight((float) AttributeUtils.calculateValue(javaAttribute));
|
||||
}
|
||||
}
|
||||
case GENERIC_GRAVITY -> {
|
||||
case GRAVITY -> {
|
||||
if (this instanceof ClientVehicle clientVehicle) {
|
||||
clientVehicle.getVehicleComponent().setGravity(AttributeUtils.calculateValue(javaAttribute));
|
||||
}
|
||||
}
|
||||
case GENERIC_ATTACK_DAMAGE -> newAttributes.add(calculateAttribute(javaAttribute, GeyserAttributeType.ATTACK_DAMAGE));
|
||||
case GENERIC_FLYING_SPEED -> newAttributes.add(calculateAttribute(javaAttribute, GeyserAttributeType.FLYING_SPEED));
|
||||
case GENERIC_FOLLOW_RANGE -> newAttributes.add(calculateAttribute(javaAttribute, GeyserAttributeType.FOLLOW_RANGE));
|
||||
case GENERIC_KNOCKBACK_RESISTANCE -> newAttributes.add(calculateAttribute(javaAttribute, GeyserAttributeType.KNOCKBACK_RESISTANCE));
|
||||
case GENERIC_JUMP_STRENGTH -> newAttributes.add(calculateAttribute(javaAttribute, GeyserAttributeType.HORSE_JUMP_STRENGTH));
|
||||
case GENERIC_SCALE -> {
|
||||
case ATTACK_DAMAGE -> newAttributes.add(calculateAttribute(javaAttribute, GeyserAttributeType.ATTACK_DAMAGE));
|
||||
case FLYING_SPEED -> newAttributes.add(calculateAttribute(javaAttribute, GeyserAttributeType.FLYING_SPEED));
|
||||
case FOLLOW_RANGE -> newAttributes.add(calculateAttribute(javaAttribute, GeyserAttributeType.FOLLOW_RANGE));
|
||||
case KNOCKBACK_RESISTANCE -> newAttributes.add(calculateAttribute(javaAttribute, GeyserAttributeType.KNOCKBACK_RESISTANCE));
|
||||
case JUMP_STRENGTH -> newAttributes.add(calculateAttribute(javaAttribute, GeyserAttributeType.HORSE_JUMP_STRENGTH));
|
||||
case SCALE -> {
|
||||
// Attribute on Java, entity data on Bedrock
|
||||
setAttributeScale((float) AttributeUtils.calculateValue(javaAttribute));
|
||||
updateBedrockMetadata();
|
||||
|
@ -0,0 +1,43 @@
|
||||
/*
|
||||
* Copyright (c) 2024 GeyserMC. http://geysermc.org
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*
|
||||
* @author GeyserMC
|
||||
* @link https://github.com/GeyserMC/Geyser
|
||||
*/
|
||||
|
||||
package org.geysermc.geyser.entity.type.living;
|
||||
|
||||
import org.cloudburstmc.math.vector.Vector3f;
|
||||
import org.geysermc.geyser.entity.EntityDefinition;
|
||||
import org.geysermc.geyser.session.GeyserSession;
|
||||
|
||||
import java.util.UUID;
|
||||
|
||||
public abstract class AgeableWaterEntity extends AgeableEntity {
|
||||
public AgeableWaterEntity(GeyserSession session, int entityId, long geyserId, UUID uuid, EntityDefinition<?> definition, Vector3f position, Vector3f motion, float yaw, float pitch, float headYaw) {
|
||||
super(session, entityId, geyserId, uuid, definition, position, motion, yaw, pitch, headYaw);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean canBeLeashed() {
|
||||
return false;
|
||||
}
|
||||
}
|
@ -37,7 +37,7 @@ import org.geysermc.mcprotocollib.protocol.data.game.entity.player.Hand;
|
||||
|
||||
import java.util.UUID;
|
||||
|
||||
public class DolphinEntity extends WaterEntity {
|
||||
public class DolphinEntity extends AgeableWaterEntity {
|
||||
public DolphinEntity(GeyserSession session, int entityId, long geyserId, UUID uuid, EntityDefinition<?> definition, Vector3f position, Vector3f motion, float yaw, float pitch, float headYaw) {
|
||||
super(session, entityId, geyserId, uuid, definition, position, motion, yaw, pitch, headYaw);
|
||||
}
|
||||
|
@ -36,7 +36,7 @@ import org.geysermc.geyser.session.GeyserSession;
|
||||
import java.util.UUID;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
|
||||
public class SquidEntity extends WaterEntity implements Tickable {
|
||||
public class SquidEntity extends AgeableWaterEntity implements Tickable {
|
||||
private float targetPitch;
|
||||
private float targetYaw;
|
||||
|
||||
|
@ -33,8 +33,9 @@ import org.cloudburstmc.protocol.bedrock.data.entity.EntityFlag;
|
||||
import org.geysermc.geyser.entity.EntityDefinition;
|
||||
import org.geysermc.geyser.entity.type.living.AgeableEntity;
|
||||
import org.geysermc.geyser.inventory.GeyserItemStack;
|
||||
import org.geysermc.geyser.item.type.Item;
|
||||
import org.geysermc.geyser.session.GeyserSession;
|
||||
import org.geysermc.geyser.session.cache.tags.ItemTag;
|
||||
import org.geysermc.geyser.session.cache.tags.Tag;
|
||||
import org.geysermc.geyser.util.InteractionResult;
|
||||
import org.geysermc.geyser.util.InteractiveTag;
|
||||
import org.geysermc.mcprotocollib.protocol.data.game.entity.player.Hand;
|
||||
@ -48,7 +49,7 @@ public abstract class AnimalEntity extends AgeableEntity {
|
||||
}
|
||||
|
||||
protected final boolean canEat(GeyserItemStack itemStack) {
|
||||
ItemTag tag = getFoodTag();
|
||||
Tag<Item> tag = getFoodTag();
|
||||
if (tag == null) {
|
||||
return false;
|
||||
}
|
||||
@ -58,7 +59,7 @@ public abstract class AnimalEntity extends AgeableEntity {
|
||||
/**
|
||||
* @return the tag associated with this animal for eating food. Null for nothing or different behavior.
|
||||
*/
|
||||
protected abstract @Nullable ItemTag getFoodTag();
|
||||
protected abstract @Nullable Tag<Item> getFoodTag();
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
|
@ -28,8 +28,10 @@ package org.geysermc.geyser.entity.type.living.animal;
|
||||
import org.checkerframework.checker.nullness.qual.Nullable;
|
||||
import org.cloudburstmc.math.vector.Vector3f;
|
||||
import org.geysermc.geyser.entity.EntityDefinition;
|
||||
import org.geysermc.geyser.item.type.Item;
|
||||
import org.geysermc.geyser.session.GeyserSession;
|
||||
import org.geysermc.geyser.session.cache.tags.ItemTag;
|
||||
import org.geysermc.geyser.session.cache.tags.Tag;
|
||||
import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.ArmadilloState;
|
||||
import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.type.ObjectEntityMetadata;
|
||||
|
||||
@ -75,7 +77,7 @@ public class ArmadilloEntity extends AnimalEntity {
|
||||
|
||||
@Override
|
||||
@Nullable
|
||||
protected ItemTag getFoodTag() {
|
||||
protected Tag<Item> getFoodTag() {
|
||||
return ItemTag.ARMADILLO_FOOD;
|
||||
}
|
||||
}
|
||||
|
@ -32,8 +32,10 @@ import org.cloudburstmc.protocol.bedrock.data.entity.EntityDataTypes;
|
||||
import org.cloudburstmc.protocol.bedrock.data.entity.EntityFlag;
|
||||
import org.geysermc.geyser.entity.EntityDefinition;
|
||||
import org.geysermc.geyser.inventory.GeyserItemStack;
|
||||
import org.geysermc.geyser.item.type.Item;
|
||||
import org.geysermc.geyser.session.GeyserSession;
|
||||
import org.geysermc.geyser.session.cache.tags.ItemTag;
|
||||
import org.geysermc.geyser.session.cache.tags.Tag;
|
||||
import org.geysermc.geyser.util.EntityUtils;
|
||||
import org.geysermc.geyser.util.InteractionResult;
|
||||
import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.type.BooleanEntityMetadata;
|
||||
@ -62,7 +64,7 @@ public class AxolotlEntity extends AnimalEntity {
|
||||
|
||||
@Override
|
||||
@Nullable
|
||||
protected ItemTag getFoodTag() {
|
||||
protected Tag<Item> getFoodTag() {
|
||||
return ItemTag.AXOLOTL_FOOD;
|
||||
}
|
||||
|
||||
|
@ -32,8 +32,10 @@ import org.cloudburstmc.protocol.bedrock.data.entity.EntityEventType;
|
||||
import org.cloudburstmc.protocol.bedrock.data.entity.EntityFlag;
|
||||
import org.cloudburstmc.protocol.bedrock.packet.EntityEventPacket;
|
||||
import org.geysermc.geyser.entity.EntityDefinition;
|
||||
import org.geysermc.geyser.item.type.Item;
|
||||
import org.geysermc.geyser.session.GeyserSession;
|
||||
import org.geysermc.geyser.session.cache.tags.ItemTag;
|
||||
import org.geysermc.geyser.session.cache.tags.Tag;
|
||||
import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.type.ByteEntityMetadata;
|
||||
import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.type.IntEntityMetadata;
|
||||
|
||||
@ -69,7 +71,7 @@ public class BeeEntity extends AnimalEntity {
|
||||
|
||||
@Override
|
||||
@Nullable
|
||||
protected ItemTag getFoodTag() {
|
||||
protected Tag<Item> getFoodTag() {
|
||||
return ItemTag.BEE_FOOD;
|
||||
}
|
||||
}
|
||||
|
@ -28,8 +28,10 @@ package org.geysermc.geyser.entity.type.living.animal;
|
||||
import org.checkerframework.checker.nullness.qual.Nullable;
|
||||
import org.cloudburstmc.math.vector.Vector3f;
|
||||
import org.geysermc.geyser.entity.EntityDefinition;
|
||||
import org.geysermc.geyser.item.type.Item;
|
||||
import org.geysermc.geyser.session.GeyserSession;
|
||||
import org.geysermc.geyser.session.cache.tags.ItemTag;
|
||||
import org.geysermc.geyser.session.cache.tags.Tag;
|
||||
|
||||
import java.util.UUID;
|
||||
|
||||
@ -41,7 +43,7 @@ public class ChickenEntity extends AnimalEntity {
|
||||
|
||||
@Override
|
||||
@Nullable
|
||||
protected ItemTag getFoodTag() {
|
||||
protected Tag<Item> getFoodTag() {
|
||||
return ItemTag.CHICKEN_FOOD;
|
||||
}
|
||||
}
|
||||
|
@ -33,8 +33,10 @@ import org.cloudburstmc.protocol.bedrock.data.entity.EntityFlag;
|
||||
import org.geysermc.geyser.entity.EntityDefinition;
|
||||
import org.geysermc.geyser.inventory.GeyserItemStack;
|
||||
import org.geysermc.geyser.item.Items;
|
||||
import org.geysermc.geyser.item.type.Item;
|
||||
import org.geysermc.geyser.session.GeyserSession;
|
||||
import org.geysermc.geyser.session.cache.tags.ItemTag;
|
||||
import org.geysermc.geyser.session.cache.tags.Tag;
|
||||
import org.geysermc.geyser.util.InteractionResult;
|
||||
import org.geysermc.geyser.util.InteractiveTag;
|
||||
import org.geysermc.mcprotocollib.protocol.data.game.entity.player.Hand;
|
||||
@ -69,7 +71,7 @@ public class CowEntity extends AnimalEntity {
|
||||
|
||||
@Override
|
||||
@Nullable
|
||||
protected ItemTag getFoodTag() {
|
||||
protected Tag<Item> getFoodTag() {
|
||||
return ItemTag.COW_FOOD;
|
||||
}
|
||||
}
|
||||
|
@ -30,8 +30,10 @@ import org.cloudburstmc.math.vector.Vector3f;
|
||||
import org.cloudburstmc.protocol.bedrock.data.entity.EntityDataTypes;
|
||||
import org.cloudburstmc.protocol.bedrock.data.entity.EntityFlag;
|
||||
import org.geysermc.geyser.entity.EntityDefinition;
|
||||
import org.geysermc.geyser.item.type.Item;
|
||||
import org.geysermc.geyser.session.GeyserSession;
|
||||
import org.geysermc.geyser.session.cache.tags.ItemTag;
|
||||
import org.geysermc.geyser.session.cache.tags.Tag;
|
||||
import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.type.ByteEntityMetadata;
|
||||
import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.type.IntEntityMetadata;
|
||||
|
||||
@ -57,7 +59,7 @@ public class FoxEntity extends AnimalEntity {
|
||||
|
||||
@Override
|
||||
@Nullable
|
||||
protected ItemTag getFoodTag() {
|
||||
protected Tag<Item> getFoodTag() {
|
||||
return ItemTag.FOX_FOOD;
|
||||
}
|
||||
}
|
||||
|
@ -31,8 +31,10 @@ import org.cloudburstmc.protocol.bedrock.data.entity.EntityDataTypes;
|
||||
import org.cloudburstmc.protocol.bedrock.data.entity.EntityFlag;
|
||||
import org.geysermc.geyser.entity.EntityDefinition;
|
||||
import org.geysermc.geyser.entity.type.Entity;
|
||||
import org.geysermc.geyser.item.type.Item;
|
||||
import org.geysermc.geyser.session.GeyserSession;
|
||||
import org.geysermc.geyser.session.cache.tags.ItemTag;
|
||||
import org.geysermc.geyser.session.cache.tags.Tag;
|
||||
import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.Pose;
|
||||
import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.type.IntEntityMetadata;
|
||||
import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.type.ObjectEntityMetadata;
|
||||
@ -77,7 +79,7 @@ public class FrogEntity extends AnimalEntity {
|
||||
|
||||
@Override
|
||||
@Nullable
|
||||
protected ItemTag getFoodTag() {
|
||||
protected Tag<Item> getFoodTag() {
|
||||
return ItemTag.FROG_FOOD;
|
||||
}
|
||||
}
|
||||
|
@ -34,8 +34,10 @@ import org.cloudburstmc.protocol.bedrock.data.entity.EntityFlag;
|
||||
import org.geysermc.geyser.entity.EntityDefinition;
|
||||
import org.geysermc.geyser.inventory.GeyserItemStack;
|
||||
import org.geysermc.geyser.item.Items;
|
||||
import org.geysermc.geyser.item.type.Item;
|
||||
import org.geysermc.geyser.session.GeyserSession;
|
||||
import org.geysermc.geyser.session.cache.tags.ItemTag;
|
||||
import org.geysermc.geyser.session.cache.tags.Tag;
|
||||
import org.geysermc.geyser.util.InteractionResult;
|
||||
import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.Pose;
|
||||
import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.type.BooleanEntityMetadata;
|
||||
@ -99,7 +101,7 @@ public class GoatEntity extends AnimalEntity {
|
||||
|
||||
@Override
|
||||
@Nullable
|
||||
protected ItemTag getFoodTag() {
|
||||
protected Tag<Item> getFoodTag() {
|
||||
return ItemTag.GOAT_FOOD;
|
||||
}
|
||||
}
|
||||
|
@ -30,8 +30,10 @@ import org.cloudburstmc.math.vector.Vector3f;
|
||||
import org.cloudburstmc.protocol.bedrock.data.entity.EntityDataTypes;
|
||||
import org.cloudburstmc.protocol.bedrock.data.entity.EntityFlag;
|
||||
import org.geysermc.geyser.entity.EntityDefinition;
|
||||
import org.geysermc.geyser.item.type.Item;
|
||||
import org.geysermc.geyser.session.GeyserSession;
|
||||
import org.geysermc.geyser.session.cache.tags.ItemTag;
|
||||
import org.geysermc.geyser.session.cache.tags.Tag;
|
||||
import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.type.BooleanEntityMetadata;
|
||||
|
||||
import java.util.UUID;
|
||||
@ -58,7 +60,7 @@ public class HoglinEntity extends AnimalEntity {
|
||||
|
||||
@Override
|
||||
@Nullable
|
||||
protected ItemTag getFoodTag() {
|
||||
protected Tag<Item> getFoodTag() {
|
||||
return ItemTag.HOGLIN_FOOD;
|
||||
}
|
||||
|
||||
|
@ -31,8 +31,10 @@ import org.cloudburstmc.math.vector.Vector3f;
|
||||
import org.cloudburstmc.protocol.bedrock.data.entity.EntityFlag;
|
||||
import org.geysermc.geyser.entity.EntityDefinition;
|
||||
import org.geysermc.geyser.inventory.GeyserItemStack;
|
||||
import org.geysermc.geyser.item.type.Item;
|
||||
import org.geysermc.geyser.session.GeyserSession;
|
||||
import org.geysermc.geyser.session.cache.tags.ItemTag;
|
||||
import org.geysermc.geyser.session.cache.tags.Tag;
|
||||
import org.geysermc.geyser.util.InteractionResult;
|
||||
import org.geysermc.geyser.util.InteractiveTag;
|
||||
import org.geysermc.mcprotocollib.protocol.data.game.entity.player.Hand;
|
||||
@ -47,7 +49,7 @@ public class OcelotEntity extends AnimalEntity {
|
||||
|
||||
@Override
|
||||
@Nullable
|
||||
protected ItemTag getFoodTag() {
|
||||
protected Tag<Item> getFoodTag() {
|
||||
return ItemTag.OCELOT_FOOD;
|
||||
}
|
||||
|
||||
|
@ -34,8 +34,10 @@ import org.cloudburstmc.protocol.bedrock.data.entity.EntityFlag;
|
||||
import org.cloudburstmc.protocol.bedrock.packet.EntityEventPacket;
|
||||
import org.geysermc.geyser.entity.EntityDefinition;
|
||||
import org.geysermc.geyser.inventory.GeyserItemStack;
|
||||
import org.geysermc.geyser.item.type.Item;
|
||||
import org.geysermc.geyser.session.GeyserSession;
|
||||
import org.geysermc.geyser.session.cache.tags.ItemTag;
|
||||
import org.geysermc.geyser.session.cache.tags.Tag;
|
||||
import org.geysermc.geyser.util.InteractionResult;
|
||||
import org.geysermc.geyser.util.InteractiveTag;
|
||||
import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.type.ByteEntityMetadata;
|
||||
@ -90,7 +92,7 @@ public class PandaEntity extends AnimalEntity {
|
||||
|
||||
@Override
|
||||
@Nullable
|
||||
protected ItemTag getFoodTag() {
|
||||
protected Tag<Item> getFoodTag() {
|
||||
return ItemTag.PANDA_FOOD;
|
||||
}
|
||||
|
||||
|
@ -38,9 +38,11 @@ import org.geysermc.geyser.entity.vehicle.BoostableVehicleComponent;
|
||||
import org.geysermc.geyser.entity.vehicle.ClientVehicle;
|
||||
import org.geysermc.geyser.entity.vehicle.VehicleComponent;
|
||||
import org.geysermc.geyser.inventory.GeyserItemStack;
|
||||
import org.geysermc.geyser.item.type.Item;
|
||||
import org.geysermc.geyser.item.Items;
|
||||
import org.geysermc.geyser.session.GeyserSession;
|
||||
import org.geysermc.geyser.session.cache.tags.ItemTag;
|
||||
import org.geysermc.geyser.session.cache.tags.Tag;
|
||||
import org.geysermc.geyser.util.EntityUtils;
|
||||
import org.geysermc.geyser.util.InteractionResult;
|
||||
import org.geysermc.geyser.util.InteractiveTag;
|
||||
@ -58,7 +60,7 @@ public class PigEntity extends AnimalEntity implements Tickable, ClientVehicle {
|
||||
|
||||
@Override
|
||||
@Nullable
|
||||
protected ItemTag getFoodTag() {
|
||||
protected Tag<Item> getFoodTag() {
|
||||
return ItemTag.PIG_FOOD;
|
||||
}
|
||||
|
||||
|
@ -28,8 +28,9 @@ package org.geysermc.geyser.entity.type.living.animal;
|
||||
import org.checkerframework.checker.nullness.qual.Nullable;
|
||||
import org.cloudburstmc.math.vector.Vector3f;
|
||||
import org.geysermc.geyser.entity.EntityDefinition;
|
||||
import org.geysermc.geyser.item.type.Item;
|
||||
import org.geysermc.geyser.session.GeyserSession;
|
||||
import org.geysermc.geyser.session.cache.tags.ItemTag;
|
||||
import org.geysermc.geyser.session.cache.tags.Tag;
|
||||
|
||||
import java.util.UUID;
|
||||
|
||||
@ -41,7 +42,7 @@ public class PolarBearEntity extends AnimalEntity {
|
||||
|
||||
@Override
|
||||
@Nullable
|
||||
protected ItemTag getFoodTag() {
|
||||
protected Tag<Item> getFoodTag() {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
@ -31,8 +31,10 @@ import org.cloudburstmc.math.vector.Vector3f;
|
||||
import org.cloudburstmc.protocol.bedrock.data.entity.EntityDataTypes;
|
||||
import org.cloudburstmc.protocol.bedrock.data.entity.EntityFlag;
|
||||
import org.geysermc.geyser.entity.EntityDefinition;
|
||||
import org.geysermc.geyser.item.type.Item;
|
||||
import org.geysermc.geyser.session.GeyserSession;
|
||||
import org.geysermc.geyser.session.cache.tags.ItemTag;
|
||||
import org.geysermc.geyser.session.cache.tags.Tag;
|
||||
import org.geysermc.geyser.util.EntityUtils;
|
||||
import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.type.IntEntityMetadata;
|
||||
|
||||
@ -79,7 +81,7 @@ public class RabbitEntity extends AnimalEntity {
|
||||
|
||||
@Override
|
||||
@Nullable
|
||||
protected ItemTag getFoodTag() {
|
||||
protected Tag<Item> getFoodTag() {
|
||||
return ItemTag.RABBIT_FOOD;
|
||||
}
|
||||
}
|
||||
|
@ -34,8 +34,10 @@ import org.geysermc.geyser.entity.EntityDefinition;
|
||||
import org.geysermc.geyser.inventory.GeyserItemStack;
|
||||
import org.geysermc.geyser.item.Items;
|
||||
import org.geysermc.geyser.item.type.DyeItem;
|
||||
import org.geysermc.geyser.item.type.Item;
|
||||
import org.geysermc.geyser.session.GeyserSession;
|
||||
import org.geysermc.geyser.session.cache.tags.ItemTag;
|
||||
import org.geysermc.geyser.session.cache.tags.Tag;
|
||||
import org.geysermc.geyser.util.InteractionResult;
|
||||
import org.geysermc.geyser.util.InteractiveTag;
|
||||
import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.type.ByteEntityMetadata;
|
||||
@ -59,7 +61,7 @@ public class SheepEntity extends AnimalEntity {
|
||||
|
||||
@Override
|
||||
@Nullable
|
||||
protected ItemTag getFoodTag() {
|
||||
protected Tag<Item> getFoodTag() {
|
||||
return ItemTag.SHEEP_FOOD;
|
||||
}
|
||||
|
||||
@ -103,4 +105,4 @@ public class SheepEntity extends AnimalEntity {
|
||||
private boolean canDye(GeyserItemStack item) {
|
||||
return item.asItem() instanceof DyeItem dyeItem && dyeItem.dyeColor() != this.color && !getFlag(EntityFlag.SHEARED);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -35,8 +35,10 @@ import org.cloudburstmc.protocol.bedrock.packet.LevelSoundEventPacket;
|
||||
import org.geysermc.geyser.entity.EntityDefinition;
|
||||
import org.geysermc.geyser.entity.EntityDefinitions;
|
||||
import org.geysermc.geyser.entity.type.Tickable;
|
||||
import org.geysermc.geyser.item.type.Item;
|
||||
import org.geysermc.geyser.session.GeyserSession;
|
||||
import org.geysermc.geyser.session.cache.tags.ItemTag;
|
||||
import org.geysermc.geyser.session.cache.tags.Tag;
|
||||
import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.Pose;
|
||||
import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.SnifferState;
|
||||
import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.type.ObjectEntityMetadata;
|
||||
@ -73,7 +75,7 @@ public class SnifferEntity extends AnimalEntity implements Tickable {
|
||||
|
||||
@Override
|
||||
@Nullable
|
||||
protected ItemTag getFoodTag() {
|
||||
protected Tag<Item> getFoodTag() {
|
||||
return ItemTag.SNIFFER_FOOD;
|
||||
}
|
||||
|
||||
|
@ -39,9 +39,11 @@ import org.geysermc.geyser.entity.vehicle.BoostableVehicleComponent;
|
||||
import org.geysermc.geyser.entity.vehicle.ClientVehicle;
|
||||
import org.geysermc.geyser.entity.vehicle.VehicleComponent;
|
||||
import org.geysermc.geyser.inventory.GeyserItemStack;
|
||||
import org.geysermc.geyser.item.type.Item;
|
||||
import org.geysermc.geyser.item.Items;
|
||||
import org.geysermc.geyser.session.GeyserSession;
|
||||
import org.geysermc.geyser.session.cache.tags.ItemTag;
|
||||
import org.geysermc.geyser.session.cache.tags.Tag;
|
||||
import org.geysermc.geyser.util.EntityUtils;
|
||||
import org.geysermc.geyser.util.InteractionResult;
|
||||
import org.geysermc.geyser.util.InteractiveTag;
|
||||
@ -105,7 +107,7 @@ public class StriderEntity extends AnimalEntity implements Tickable, ClientVehic
|
||||
|
||||
@Override
|
||||
@Nullable
|
||||
protected ItemTag getFoodTag() {
|
||||
protected Tag<Item> getFoodTag() {
|
||||
return ItemTag.STRIDER_FOOD;
|
||||
}
|
||||
|
||||
|
@ -29,8 +29,10 @@ import org.checkerframework.checker.nullness.qual.Nullable;
|
||||
import org.cloudburstmc.math.vector.Vector3f;
|
||||
import org.cloudburstmc.protocol.bedrock.data.entity.EntityFlag;
|
||||
import org.geysermc.geyser.entity.EntityDefinition;
|
||||
import org.geysermc.geyser.item.type.Item;
|
||||
import org.geysermc.geyser.session.GeyserSession;
|
||||
import org.geysermc.geyser.session.cache.tags.ItemTag;
|
||||
import org.geysermc.geyser.session.cache.tags.Tag;
|
||||
import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.type.BooleanEntityMetadata;
|
||||
|
||||
import java.util.UUID;
|
||||
@ -51,7 +53,7 @@ public class TurtleEntity extends AnimalEntity {
|
||||
|
||||
@Override
|
||||
@Nullable
|
||||
protected ItemTag getFoodTag() {
|
||||
protected Tag<Item> getFoodTag() {
|
||||
return ItemTag.TURTLE_FOOD;
|
||||
}
|
||||
|
||||
|
@ -39,8 +39,10 @@ import org.geysermc.geyser.entity.attribute.GeyserAttributeType;
|
||||
import org.geysermc.geyser.entity.type.living.animal.AnimalEntity;
|
||||
import org.geysermc.geyser.inventory.GeyserItemStack;
|
||||
import org.geysermc.geyser.item.Items;
|
||||
import org.geysermc.geyser.item.type.Item;
|
||||
import org.geysermc.geyser.session.GeyserSession;
|
||||
import org.geysermc.geyser.session.cache.tags.ItemTag;
|
||||
import org.geysermc.geyser.session.cache.tags.Tag;
|
||||
import org.geysermc.geyser.util.InteractionResult;
|
||||
import org.geysermc.geyser.util.InteractiveTag;
|
||||
import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.type.ByteEntityMetadata;
|
||||
@ -119,7 +121,7 @@ public class AbstractHorseEntity extends AnimalEntity {
|
||||
|
||||
@Override
|
||||
@Nullable
|
||||
protected ItemTag getFoodTag() {
|
||||
protected Tag<Item> getFoodTag() {
|
||||
return ItemTag.HORSE_FOOD;
|
||||
}
|
||||
|
||||
|
@ -35,12 +35,14 @@ import org.cloudburstmc.protocol.bedrock.data.entity.EntityFlag;
|
||||
import org.cloudburstmc.protocol.bedrock.data.inventory.ContainerType;
|
||||
import org.cloudburstmc.protocol.bedrock.packet.EntityEventPacket;
|
||||
import org.geysermc.geyser.entity.EntityDefinition;
|
||||
import org.geysermc.geyser.item.type.Item;
|
||||
import org.geysermc.geyser.entity.attribute.GeyserAttributeType;
|
||||
import org.geysermc.geyser.entity.vehicle.CamelVehicleComponent;
|
||||
import org.geysermc.geyser.entity.vehicle.ClientVehicle;
|
||||
import org.geysermc.geyser.entity.vehicle.VehicleComponent;
|
||||
import org.geysermc.geyser.session.GeyserSession;
|
||||
import org.geysermc.geyser.session.cache.tags.ItemTag;
|
||||
import org.geysermc.geyser.session.cache.tags.Tag;
|
||||
import org.geysermc.mcprotocollib.protocol.data.game.entity.attribute.Attribute;
|
||||
import org.geysermc.mcprotocollib.protocol.data.game.entity.attribute.AttributeType;
|
||||
import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.Pose;
|
||||
@ -100,7 +102,7 @@ public class CamelEntity extends AbstractHorseEntity implements ClientVehicle {
|
||||
}
|
||||
|
||||
@Override
|
||||
protected @Nullable ItemTag getFoodTag() {
|
||||
protected @Nullable Tag<Item> getFoodTag() {
|
||||
return ItemTag.CAMEL_FOOD;
|
||||
}
|
||||
|
||||
@ -141,7 +143,7 @@ public class CamelEntity extends AbstractHorseEntity implements ClientVehicle {
|
||||
@Override
|
||||
protected AttributeData calculateAttribute(Attribute javaAttribute, GeyserAttributeType type) {
|
||||
AttributeData attributeData = super.calculateAttribute(javaAttribute, type);
|
||||
if (javaAttribute.getType() == AttributeType.Builtin.GENERIC_JUMP_STRENGTH) {
|
||||
if (javaAttribute.getType() == AttributeType.Builtin.JUMP_STRENGTH) {
|
||||
vehicleComponent.setHorseJumpStrength(attributeData.getValue());
|
||||
}
|
||||
return attributeData;
|
||||
|
@ -30,8 +30,10 @@ import org.checkerframework.checker.nullness.qual.Nullable;
|
||||
import org.cloudburstmc.math.vector.Vector3f;
|
||||
import org.cloudburstmc.protocol.bedrock.data.entity.EntityDataTypes;
|
||||
import org.geysermc.geyser.entity.EntityDefinition;
|
||||
import org.geysermc.geyser.item.type.Item;
|
||||
import org.geysermc.geyser.session.GeyserSession;
|
||||
import org.geysermc.geyser.session.cache.tags.ItemTag;
|
||||
import org.geysermc.geyser.session.cache.tags.Tag;
|
||||
import org.geysermc.geyser.util.MathUtils;
|
||||
import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.type.IntEntityMetadata;
|
||||
|
||||
@ -56,7 +58,7 @@ public class LlamaEntity extends ChestedHorseEntity {
|
||||
}
|
||||
|
||||
@Override
|
||||
protected @Nullable ItemTag getFoodTag() {
|
||||
protected @Nullable Tag<Item> getFoodTag() {
|
||||
return ItemTag.LLAMA_FOOD;
|
||||
}
|
||||
}
|
||||
|
@ -32,8 +32,10 @@ import org.cloudburstmc.protocol.bedrock.data.entity.EntityDataTypes;
|
||||
import org.cloudburstmc.protocol.bedrock.data.entity.EntityFlag;
|
||||
import org.geysermc.geyser.entity.EntityDefinition;
|
||||
import org.geysermc.geyser.inventory.GeyserItemStack;
|
||||
import org.geysermc.geyser.item.type.Item;
|
||||
import org.geysermc.geyser.session.GeyserSession;
|
||||
import org.geysermc.geyser.session.cache.tags.ItemTag;
|
||||
import org.geysermc.geyser.session.cache.tags.Tag;
|
||||
import org.geysermc.geyser.util.InteractionResult;
|
||||
import org.geysermc.geyser.util.InteractiveTag;
|
||||
import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.type.BooleanEntityMetadata;
|
||||
@ -109,7 +111,7 @@ public class CatEntity extends TameableEntity {
|
||||
}
|
||||
|
||||
@Override
|
||||
protected @Nullable ItemTag getFoodTag() {
|
||||
protected @Nullable Tag<Item> getFoodTag() {
|
||||
return ItemTag.CAT_FOOD;
|
||||
}
|
||||
|
||||
|
@ -34,6 +34,7 @@ import org.geysermc.geyser.inventory.GeyserItemStack;
|
||||
import org.geysermc.geyser.item.type.Item;
|
||||
import org.geysermc.geyser.session.GeyserSession;
|
||||
import org.geysermc.geyser.session.cache.tags.ItemTag;
|
||||
import org.geysermc.geyser.session.cache.tags.Tag;
|
||||
import org.geysermc.geyser.util.InteractionResult;
|
||||
import org.geysermc.geyser.util.InteractiveTag;
|
||||
import org.geysermc.mcprotocollib.protocol.data.game.entity.player.Hand;
|
||||
@ -47,7 +48,7 @@ public class ParrotEntity extends TameableEntity {
|
||||
|
||||
@Override
|
||||
@Nullable
|
||||
protected ItemTag getFoodTag() {
|
||||
protected Tag<Item> getFoodTag() {
|
||||
return null;
|
||||
}
|
||||
|
||||
|
@ -36,8 +36,10 @@ import org.geysermc.geyser.inventory.GeyserItemStack;
|
||||
import org.geysermc.geyser.item.Items;
|
||||
import org.geysermc.geyser.item.enchantment.EnchantmentComponent;
|
||||
import org.geysermc.geyser.item.type.DyeItem;
|
||||
import org.geysermc.geyser.item.type.Item;
|
||||
import org.geysermc.geyser.session.GeyserSession;
|
||||
import org.geysermc.geyser.session.cache.tags.ItemTag;
|
||||
import org.geysermc.geyser.session.cache.tags.Tag;
|
||||
import org.geysermc.geyser.util.InteractionResult;
|
||||
import org.geysermc.geyser.util.InteractiveTag;
|
||||
import org.geysermc.geyser.util.ItemUtils;
|
||||
@ -116,7 +118,7 @@ public class WolfEntity extends TameableEntity {
|
||||
|
||||
@Override
|
||||
@Nullable
|
||||
protected ItemTag getFoodTag() {
|
||||
protected Tag<Item> getFoodTag() {
|
||||
return ItemTag.WOLF_FOOD;
|
||||
}
|
||||
|
||||
|
@ -25,12 +25,6 @@
|
||||
|
||||
package org.geysermc.geyser.entity.type.player;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
import java.util.Optional;
|
||||
import java.util.UUID;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
import net.kyori.adventure.text.Component;
|
||||
@ -65,6 +59,13 @@ import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.type.Boolea
|
||||
import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.type.ByteEntityMetadata;
|
||||
import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.type.FloatEntityMetadata;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
import java.util.Optional;
|
||||
import java.util.UUID;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
@Getter @Setter
|
||||
public class PlayerEntity extends LivingEntity implements GeyserPlayerEntity {
|
||||
public static final float SNEAKING_POSE_HEIGHT = 1.5f;
|
||||
@ -250,10 +251,6 @@ public class PlayerEntity extends LivingEntity implements GeyserPlayerEntity {
|
||||
}
|
||||
}
|
||||
|
||||
public void updateRotation(float yaw, float pitch, float headYaw, boolean isOnGround) {
|
||||
moveRelative(0, 0, 0, yaw, pitch, headYaw, isOnGround);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setPosition(Vector3f position) {
|
||||
if (this.bedPosition != null) {
|
||||
|
@ -38,8 +38,8 @@ import org.cloudburstmc.protocol.bedrock.packet.MovePlayerPacket;
|
||||
import org.cloudburstmc.protocol.bedrock.packet.UpdateAttributesPacket;
|
||||
import org.geysermc.geyser.entity.attribute.GeyserAttributeType;
|
||||
import org.geysermc.geyser.item.Items;
|
||||
import org.geysermc.geyser.network.GameProtocol;
|
||||
import org.geysermc.geyser.level.BedrockDimension;
|
||||
import org.geysermc.geyser.network.GameProtocol;
|
||||
import org.geysermc.geyser.session.GeyserSession;
|
||||
import org.geysermc.geyser.util.AttributeUtils;
|
||||
import org.geysermc.geyser.util.DimensionUtils;
|
||||
@ -143,9 +143,32 @@ public class SessionPlayerEntity extends PlayerEntity {
|
||||
this.position = position.add(0, definition.offset(), 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Special method used only when updating the session player's rotation.
|
||||
* For some reason, Mode#NORMAL ignored rotation. Yay.
|
||||
* @param yaw the new yaw
|
||||
* @param pitch the new pitch
|
||||
* @param headYaw the head yaw
|
||||
*/
|
||||
public void updateOwnRotation(float yaw, float pitch, float headYaw) {
|
||||
setYaw(yaw);
|
||||
setPitch(pitch);
|
||||
setHeadYaw(headYaw);
|
||||
|
||||
MovePlayerPacket movePlayerPacket = new MovePlayerPacket();
|
||||
movePlayerPacket.setRuntimeEntityId(geyserId);
|
||||
movePlayerPacket.setPosition(position);
|
||||
movePlayerPacket.setRotation(getBedrockRotation());
|
||||
movePlayerPacket.setOnGround(isOnGround());
|
||||
movePlayerPacket.setMode(MovePlayerPacket.Mode.TELEPORT);
|
||||
movePlayerPacket.setTeleportationCause(MovePlayerPacket.TeleportationCause.BEHAVIOR);
|
||||
|
||||
session.sendUpstreamPacket(movePlayerPacket);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the player's position without applying an offset or moving the bounding box
|
||||
* This is used in BedrockMovePlayerTranslator which receives the player's position
|
||||
* This is used in BedrockMovePlayer which receives the player's position
|
||||
* with the offset pre-applied
|
||||
*
|
||||
* @param position the new position of the Bedrock player
|
||||
@ -247,9 +270,9 @@ public class SessionPlayerEntity extends PlayerEntity {
|
||||
|
||||
@Override
|
||||
protected void updateAttribute(Attribute javaAttribute, List<AttributeData> newAttributes) {
|
||||
if (javaAttribute.getType() == AttributeType.Builtin.GENERIC_ATTACK_SPEED) {
|
||||
if (javaAttribute.getType() == AttributeType.Builtin.ATTACK_SPEED) {
|
||||
session.setAttackSpeed(AttributeUtils.calculateValue(javaAttribute));
|
||||
} else if (javaAttribute.getType() == AttributeType.Builtin.PLAYER_BLOCK_INTERACTION_RANGE) {
|
||||
} else if (javaAttribute.getType() == AttributeType.Builtin.BLOCK_INTERACTION_RANGE) {
|
||||
this.blockInteractionRange = AttributeUtils.calculateValue(javaAttribute);
|
||||
} else {
|
||||
super.updateAttribute(javaAttribute, newAttributes);
|
||||
|
@ -76,8 +76,8 @@ public class VehicleComponent<T extends LivingEntity & ClientVehicle> {
|
||||
public VehicleComponent(T vehicle, float stepHeight) {
|
||||
this.vehicle = vehicle;
|
||||
this.stepHeight = stepHeight;
|
||||
this.moveSpeed = (float) AttributeType.Builtin.GENERIC_MOVEMENT_SPEED.getDef();
|
||||
this.gravity = AttributeType.Builtin.GENERIC_GRAVITY.getDef();
|
||||
this.moveSpeed = (float) AttributeType.Builtin.MOVEMENT_SPEED.getDef();
|
||||
this.gravity = AttributeType.Builtin.GRAVITY.getDef();
|
||||
|
||||
double width = vehicle.getBoundingBoxWidth();
|
||||
double height = vehicle.getBoundingBoxHeight();
|
||||
@ -758,7 +758,6 @@ public class VehicleComponent<T extends LivingEntity & ClientVehicle> {
|
||||
|
||||
ServerboundMoveVehiclePacket moveVehiclePacket = new ServerboundMoveVehiclePacket(javaPos.getX(), javaPos.getY(), javaPos.getZ(), rotation.getX(), rotation.getY());
|
||||
vehicle.getSession().sendDownstreamPacket(moveVehiclePacket);
|
||||
vehicle.getSession().setLastVehicleMoveTimestamp(System.currentTimeMillis());
|
||||
}
|
||||
|
||||
protected double getGravity() {
|
||||
|
@ -29,6 +29,7 @@ import lombok.*;
|
||||
import org.checkerframework.checker.nullness.qual.NonNull;
|
||||
import org.checkerframework.checker.nullness.qual.Nullable;
|
||||
import org.cloudburstmc.protocol.bedrock.data.inventory.ItemData;
|
||||
import org.geysermc.geyser.GeyserImpl;
|
||||
import org.geysermc.geyser.item.Items;
|
||||
import org.geysermc.geyser.item.type.Item;
|
||||
import org.geysermc.geyser.registry.Registries;
|
||||
@ -38,6 +39,10 @@ import org.geysermc.geyser.translator.item.ItemTranslator;
|
||||
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.DataComponents;
|
||||
import org.geysermc.mcprotocollib.protocol.data.game.recipe.display.slot.EmptySlotDisplay;
|
||||
import org.geysermc.mcprotocollib.protocol.data.game.recipe.display.slot.ItemSlotDisplay;
|
||||
import org.geysermc.mcprotocollib.protocol.data.game.recipe.display.slot.ItemStackSlotDisplay;
|
||||
import org.geysermc.mcprotocollib.protocol.data.game.recipe.display.slot.SlotDisplay;
|
||||
|
||||
import java.util.HashMap;
|
||||
|
||||
@ -77,6 +82,20 @@ public class GeyserItemStack {
|
||||
return itemStack == null ? EMPTY : new GeyserItemStack(itemStack.getId(), itemStack.getAmount(), itemStack.getDataComponents());
|
||||
}
|
||||
|
||||
public static @NonNull GeyserItemStack from(@NonNull SlotDisplay slotDisplay) {
|
||||
if (slotDisplay instanceof EmptySlotDisplay) {
|
||||
return GeyserItemStack.EMPTY;
|
||||
}
|
||||
if (slotDisplay instanceof ItemSlotDisplay itemSlotDisplay) {
|
||||
return GeyserItemStack.of(itemSlotDisplay.item(), 1);
|
||||
}
|
||||
if (slotDisplay instanceof ItemStackSlotDisplay itemStackSlotDisplay) {
|
||||
return GeyserItemStack.from(itemStackSlotDisplay.itemStack());
|
||||
}
|
||||
GeyserImpl.getInstance().getLogger().warning("Unsure how to convert to ItemStack: " + slotDisplay);
|
||||
return GeyserItemStack.EMPTY;
|
||||
}
|
||||
|
||||
public int getJavaId() {
|
||||
return isEmpty() ? 0 : javaId;
|
||||
}
|
||||
@ -163,7 +182,17 @@ public class GeyserItemStack {
|
||||
return session.getItemMappings().getMapping(this.javaId);
|
||||
}
|
||||
|
||||
public SlotDisplay asSlotDisplay() {
|
||||
if (isEmpty()) {
|
||||
return EmptySlotDisplay.INSTANCE;
|
||||
}
|
||||
return new ItemStackSlotDisplay(this.getItemStack());
|
||||
}
|
||||
|
||||
public Item asItem() {
|
||||
if (isEmpty()) {
|
||||
return Items.AIR;
|
||||
}
|
||||
if (item == null) {
|
||||
return (item = Registries.JAVA_ITEMS.get().get(javaId));
|
||||
}
|
||||
|
@ -0,0 +1,166 @@
|
||||
/*
|
||||
* Copyright (c) 2024 GeyserMC. http://geysermc.org
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*
|
||||
* @author GeyserMC
|
||||
* @link https://github.com/GeyserMC/Geyser
|
||||
*/
|
||||
|
||||
package org.geysermc.geyser.inventory.item;
|
||||
|
||||
import net.kyori.adventure.key.Key;
|
||||
import org.checkerframework.checker.nullness.qual.Nullable;
|
||||
import org.cloudburstmc.nbt.NbtMap;
|
||||
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.translator.text.MessageTranslator;
|
||||
import org.geysermc.geyser.util.MinecraftKey;
|
||||
import org.geysermc.geyser.util.SoundUtils;
|
||||
import org.geysermc.mcprotocollib.protocol.data.game.Holder;
|
||||
import org.geysermc.mcprotocollib.protocol.data.game.item.component.Instrument;
|
||||
import org.geysermc.mcprotocollib.protocol.data.game.level.sound.BuiltinSound;
|
||||
|
||||
import java.util.Locale;
|
||||
|
||||
public interface GeyserInstrument {
|
||||
|
||||
static GeyserInstrument read(RegistryEntryContext context) {
|
||||
NbtMap data = context.data();
|
||||
String soundEvent = SoundUtils.readSoundEvent(data, "instrument " + context.id());
|
||||
float range = data.getFloat("range");
|
||||
String description = MessageTranslator.deserializeDescriptionForTooltip(context.session(), data);
|
||||
BedrockInstrument bedrockInstrument = BedrockInstrument.getByJavaIdentifier(context.id());
|
||||
return new GeyserInstrument.Impl(soundEvent, range, description, bedrockInstrument);
|
||||
}
|
||||
|
||||
String soundEvent();
|
||||
|
||||
float range();
|
||||
|
||||
/**
|
||||
* In Bedrock format
|
||||
*/
|
||||
String description();
|
||||
|
||||
BedrockInstrument bedrockInstrument();
|
||||
|
||||
/**
|
||||
* @return the ID of the Bedrock counterpart for this instrument. If there is none ({@link #bedrockInstrument()} is null), then -1 is returned.
|
||||
*/
|
||||
default int bedrockId() {
|
||||
BedrockInstrument bedrockInstrument = bedrockInstrument();
|
||||
if (bedrockInstrument != null) {
|
||||
return bedrockInstrument.ordinal();
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the ID of the Java counterpart for the given Bedrock ID. If an invalid Bedrock ID was given, or there is no counterpart, -1 is returned.
|
||||
*/
|
||||
static int bedrockIdToJava(GeyserSession session, int id) {
|
||||
JavaRegistry<GeyserInstrument> instruments = session.getRegistryCache().instruments();
|
||||
BedrockInstrument bedrockInstrument = BedrockInstrument.getByBedrockId(id);
|
||||
if (bedrockInstrument != null) {
|
||||
for (int i = 0; i < instruments.values().size(); i++) {
|
||||
GeyserInstrument instrument = instruments.byId(i);
|
||||
if (instrument.bedrockInstrument() == bedrockInstrument) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
static GeyserInstrument fromHolder(GeyserSession session, Holder<Instrument> holder) {
|
||||
if (holder.isId()) {
|
||||
return session.getRegistryCache().instruments().byId(holder.id());
|
||||
}
|
||||
Instrument custom = holder.custom();
|
||||
return new Wrapper(custom, session.locale());
|
||||
}
|
||||
|
||||
record Wrapper(Instrument instrument, String locale) implements GeyserInstrument {
|
||||
@Override
|
||||
public String soundEvent() {
|
||||
return instrument.getSoundEvent().getName();
|
||||
}
|
||||
|
||||
@Override
|
||||
public float range() {
|
||||
return instrument.getRange();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String description() {
|
||||
return MessageTranslator.convertMessageForTooltip(instrument.getDescription(), locale);
|
||||
}
|
||||
|
||||
@Override
|
||||
public BedrockInstrument bedrockInstrument() {
|
||||
if (instrument.getSoundEvent() instanceof BuiltinSound) {
|
||||
return BedrockInstrument.getByJavaIdentifier(MinecraftKey.key(instrument.getSoundEvent().getName()));
|
||||
}
|
||||
// Probably custom
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
record Impl(String soundEvent, float range, String description, @Nullable BedrockInstrument bedrockInstrument) implements GeyserInstrument {
|
||||
}
|
||||
|
||||
/**
|
||||
* Each vanilla instrument on Bedrock, ordered in their network IDs.
|
||||
*/
|
||||
enum BedrockInstrument {
|
||||
PONDER,
|
||||
SING,
|
||||
SEEK,
|
||||
FEEL,
|
||||
ADMIRE,
|
||||
CALL,
|
||||
YEARN,
|
||||
DREAM;
|
||||
|
||||
private static final BedrockInstrument[] VALUES = values();
|
||||
private final Key javaIdentifier;
|
||||
|
||||
BedrockInstrument() {
|
||||
this.javaIdentifier = MinecraftKey.key(this.name().toLowerCase(Locale.ENGLISH) + "_goat_horn");
|
||||
}
|
||||
|
||||
public static @Nullable BedrockInstrument getByJavaIdentifier(Key javaIdentifier) {
|
||||
for (BedrockInstrument instrument : VALUES) {
|
||||
if (instrument.javaIdentifier.equals(javaIdentifier)) {
|
||||
return instrument;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public static @Nullable BedrockInstrument getByBedrockId(int bedrockId) {
|
||||
if (bedrockId >= 0 && bedrockId < VALUES.length) {
|
||||
return VALUES[bedrockId];
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
@ -99,7 +99,7 @@ public enum Potion {
|
||||
}
|
||||
|
||||
public PotionContents toComponent() {
|
||||
return new PotionContents(this.ordinal(), -1, Collections.emptyList());
|
||||
return new PotionContents(this.ordinal(), -1, Collections.emptyList(), null);
|
||||
}
|
||||
|
||||
public static Potion getByJavaIdentifier(String javaIdentifier) {
|
||||
|
@ -25,11 +25,10 @@
|
||||
|
||||
package org.geysermc.geyser.inventory.recipe;
|
||||
|
||||
import org.checkerframework.checker.nullness.qual.Nullable;
|
||||
import org.geysermc.mcprotocollib.protocol.data.game.item.ItemStack;
|
||||
import org.geysermc.mcprotocollib.protocol.data.game.recipe.display.slot.SlotDisplay;
|
||||
|
||||
/**
|
||||
* A more compact version of {@link org.geysermc.mcprotocollib.protocol.data.game.recipe.Recipe}.
|
||||
* A more compact version of {@link org.geysermc.mcprotocollib.protocol.data.game.recipe.display.RecipeDisplay}.
|
||||
*/
|
||||
public interface GeyserRecipe {
|
||||
/**
|
||||
@ -37,6 +36,5 @@ public interface GeyserRecipe {
|
||||
*/
|
||||
boolean isShaped();
|
||||
|
||||
@Nullable
|
||||
ItemStack result();
|
||||
SlotDisplay result();
|
||||
}
|
||||
|
@ -25,15 +25,15 @@
|
||||
|
||||
package org.geysermc.geyser.inventory.recipe;
|
||||
|
||||
import org.checkerframework.checker.nullness.qual.Nullable;
|
||||
import org.geysermc.mcprotocollib.protocol.data.game.item.ItemStack;
|
||||
import org.geysermc.mcprotocollib.protocol.data.game.recipe.Ingredient;
|
||||
import org.geysermc.mcprotocollib.protocol.data.game.recipe.data.ShapedRecipeData;
|
||||
import org.geysermc.mcprotocollib.protocol.data.game.recipe.display.ShapedCraftingRecipeDisplay;
|
||||
import org.geysermc.mcprotocollib.protocol.data.game.recipe.display.slot.SlotDisplay;
|
||||
|
||||
public record GeyserShapedRecipe(int width, int height, Ingredient[] ingredients, @Nullable ItemStack result) implements GeyserRecipe {
|
||||
import java.util.List;
|
||||
|
||||
public GeyserShapedRecipe(ShapedRecipeData data) {
|
||||
this(data.getWidth(), data.getHeight(), data.getIngredients(), data.getResult());
|
||||
public record GeyserShapedRecipe(int width, int height, List<SlotDisplay> ingredients, SlotDisplay result) implements GeyserRecipe {
|
||||
|
||||
public GeyserShapedRecipe(ShapedCraftingRecipeDisplay data) {
|
||||
this(data.width(), data.height(), data.ingredients(), data.result());
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -25,15 +25,15 @@
|
||||
|
||||
package org.geysermc.geyser.inventory.recipe;
|
||||
|
||||
import org.geysermc.mcprotocollib.protocol.data.game.item.ItemStack;
|
||||
import org.geysermc.mcprotocollib.protocol.data.game.recipe.Ingredient;
|
||||
import org.geysermc.mcprotocollib.protocol.data.game.recipe.data.ShapelessRecipeData;
|
||||
import org.checkerframework.checker.nullness.qual.Nullable;
|
||||
import org.geysermc.mcprotocollib.protocol.data.game.recipe.display.ShapelessCraftingRecipeDisplay;
|
||||
import org.geysermc.mcprotocollib.protocol.data.game.recipe.display.slot.SlotDisplay;
|
||||
|
||||
public record GeyserShapelessRecipe(Ingredient[] ingredients, @Nullable ItemStack result) implements GeyserRecipe {
|
||||
import java.util.List;
|
||||
|
||||
public GeyserShapelessRecipe(ShapelessRecipeData data) {
|
||||
this(data.getIngredients(), data.getResult());
|
||||
public record GeyserShapelessRecipe(List<SlotDisplay> ingredients, SlotDisplay result) implements GeyserRecipe {
|
||||
|
||||
public GeyserShapelessRecipe(ShapelessCraftingRecipeDisplay data) {
|
||||
this(data.ingredients(), data.result());
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -0,0 +1,43 @@
|
||||
/*
|
||||
* Copyright (c) 2024 GeyserMC. http://geysermc.org
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*
|
||||
* @author GeyserMC
|
||||
* @link https://github.com/GeyserMC/Geyser
|
||||
*/
|
||||
|
||||
package org.geysermc.geyser.inventory.recipe;
|
||||
|
||||
import org.geysermc.mcprotocollib.protocol.data.game.recipe.display.SmithingRecipeDisplay;
|
||||
import org.geysermc.mcprotocollib.protocol.data.game.recipe.display.slot.SlotDisplay;
|
||||
|
||||
public record GeyserSmithingRecipe(SlotDisplay template,
|
||||
SlotDisplay base,
|
||||
SlotDisplay addition,
|
||||
SlotDisplay result) implements GeyserRecipe {
|
||||
public GeyserSmithingRecipe(SmithingRecipeDisplay display) {
|
||||
this(display.template(), display.base(), display.addition(), display.result());
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isShaped() {
|
||||
return false;
|
||||
}
|
||||
}
|
@ -41,17 +41,15 @@ import org.geysermc.geyser.inventory.item.BedrockEnchantment;
|
||||
import org.geysermc.geyser.item.Items;
|
||||
import org.geysermc.geyser.item.enchantment.Enchantment;
|
||||
import org.geysermc.geyser.session.GeyserSession;
|
||||
import org.geysermc.geyser.session.cache.tags.EnchantmentTag;
|
||||
import org.geysermc.geyser.session.cache.tags.ItemTag;
|
||||
import org.geysermc.geyser.translator.inventory.InventoryTranslator;
|
||||
import org.geysermc.geyser.translator.text.MessageTranslator;
|
||||
import org.geysermc.geyser.util.ItemUtils;
|
||||
import org.geysermc.mcprotocollib.protocol.data.game.entity.player.GameMode;
|
||||
import org.geysermc.mcprotocollib.protocol.data.game.item.component.DataComponentType;
|
||||
import org.geysermc.mcprotocollib.protocol.data.game.item.component.HolderSet;
|
||||
import org.geysermc.mcprotocollib.protocol.data.game.item.component.ItemEnchantments;
|
||||
import org.geysermc.mcprotocollib.protocol.packet.ingame.serverbound.inventory.ServerboundRenameItemPacket;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.stream.IntStream;
|
||||
@ -314,14 +312,10 @@ public class AnvilInventoryUpdater extends InventoryUpdater {
|
||||
for (Object2IntMap.Entry<Enchantment> entry : getEnchantments(session, material).object2IntEntrySet()) {
|
||||
Enchantment enchantment = entry.getKey();
|
||||
|
||||
HolderSet supportedItems = enchantment.supportedItems();
|
||||
int[] supportedItemIds = supportedItems.resolve(tagId -> session.getTagCache().get(ItemTag.ALL_ITEM_TAGS.get(tagId)));
|
||||
boolean canApply = isEnchantedBook(input) || IntStream.of(supportedItemIds).anyMatch(id -> id == input.getJavaId());
|
||||
boolean canApply = isEnchantedBook(input) || session.getTagCache().is(enchantment.supportedItems(), input.asItem());
|
||||
|
||||
HolderSet exclusiveSet = enchantment.exclusiveSet();
|
||||
int[] incompatibleEnchantments = exclusiveSet.resolve(tagId -> session.getTagCache().get(EnchantmentTag.ALL_ENCHANTMENT_TAGS.get(tagId)));
|
||||
for (int i : incompatibleEnchantments) {
|
||||
Enchantment incompatible = session.getRegistryCache().enchantments().byId(i);
|
||||
List<Enchantment> incompatibleEnchantments = enchantment.exclusiveSet().resolve(session);
|
||||
for (Enchantment incompatible : incompatibleEnchantments) {
|
||||
if (combinedEnchantments.containsKey(incompatible)) {
|
||||
canApply = false;
|
||||
if (!bedrock) {
|
||||
|
@ -25,9 +25,39 @@
|
||||
|
||||
package org.geysermc.geyser.item;
|
||||
|
||||
import org.geysermc.geyser.item.components.Rarity;
|
||||
import org.geysermc.geyser.item.components.ToolTier;
|
||||
import org.geysermc.geyser.item.type.*;
|
||||
import org.geysermc.geyser.item.type.ArmorItem;
|
||||
import org.geysermc.geyser.item.type.ArrowItem;
|
||||
import org.geysermc.geyser.item.type.AxolotlBucketItem;
|
||||
import org.geysermc.geyser.item.type.BannerItem;
|
||||
import org.geysermc.geyser.item.type.BlockItem;
|
||||
import org.geysermc.geyser.item.type.BoatItem;
|
||||
import org.geysermc.geyser.item.type.CompassItem;
|
||||
import org.geysermc.geyser.item.type.CrossbowItem;
|
||||
import org.geysermc.geyser.item.type.DecoratedPotItem;
|
||||
import org.geysermc.geyser.item.type.DyeItem;
|
||||
import org.geysermc.geyser.item.type.DyeableArmorItem;
|
||||
import org.geysermc.geyser.item.type.ElytraItem;
|
||||
import org.geysermc.geyser.item.type.EnchantedBookItem;
|
||||
import org.geysermc.geyser.item.type.FilledMapItem;
|
||||
import org.geysermc.geyser.item.type.FireworkRocketItem;
|
||||
import org.geysermc.geyser.item.type.FireworkStarItem;
|
||||
import org.geysermc.geyser.item.type.FishingRodItem;
|
||||
import org.geysermc.geyser.item.type.GoatHornItem;
|
||||
import org.geysermc.geyser.item.type.Item;
|
||||
import org.geysermc.geyser.item.type.MaceItem;
|
||||
import org.geysermc.geyser.item.type.MapItem;
|
||||
import org.geysermc.geyser.item.type.PlayerHeadItem;
|
||||
import org.geysermc.geyser.item.type.PotionItem;
|
||||
import org.geysermc.geyser.item.type.ShieldItem;
|
||||
import org.geysermc.geyser.item.type.ShulkerBoxItem;
|
||||
import org.geysermc.geyser.item.type.SpawnEggItem;
|
||||
import org.geysermc.geyser.item.type.TieredItem;
|
||||
import org.geysermc.geyser.item.type.TippedArrowItem;
|
||||
import org.geysermc.geyser.item.type.TropicalFishBucketItem;
|
||||
import org.geysermc.geyser.item.type.WolfArmorItem;
|
||||
import org.geysermc.geyser.item.type.WritableBookItem;
|
||||
import org.geysermc.geyser.item.type.WrittenBookItem;
|
||||
import org.geysermc.geyser.level.block.Blocks;
|
||||
import org.geysermc.geyser.registry.Registries;
|
||||
|
||||
@ -81,6 +111,7 @@ public final class Items {
|
||||
public static final Item ACACIA_PLANKS = register(new BlockItem(builder(), Blocks.ACACIA_PLANKS));
|
||||
public static final Item CHERRY_PLANKS = register(new BlockItem(builder(), Blocks.CHERRY_PLANKS));
|
||||
public static final Item DARK_OAK_PLANKS = register(new BlockItem(builder(), Blocks.DARK_OAK_PLANKS));
|
||||
public static final Item PALE_OAK_PLANKS = register(new BlockItem(builder(), Blocks.PALE_OAK_PLANKS));
|
||||
public static final Item MANGROVE_PLANKS = register(new BlockItem(builder(), Blocks.MANGROVE_PLANKS));
|
||||
public static final Item BAMBOO_PLANKS = register(new BlockItem(builder(), Blocks.BAMBOO_PLANKS));
|
||||
public static final Item CRIMSON_PLANKS = register(new BlockItem(builder(), Blocks.CRIMSON_PLANKS));
|
||||
@ -93,6 +124,7 @@ public final class Items {
|
||||
public static final Item ACACIA_SAPLING = register(new BlockItem(builder(), Blocks.ACACIA_SAPLING));
|
||||
public static final Item CHERRY_SAPLING = register(new BlockItem(builder(), Blocks.CHERRY_SAPLING));
|
||||
public static final Item DARK_OAK_SAPLING = register(new BlockItem(builder(), Blocks.DARK_OAK_SAPLING));
|
||||
public static final Item PALE_OAK_SAPLING = register(new BlockItem(builder(), Blocks.PALE_OAK_SAPLING));
|
||||
public static final Item MANGROVE_PROPAGULE = register(new BlockItem(builder(), Blocks.MANGROVE_PROPAGULE));
|
||||
public static final Item BEDROCK = register(new BlockItem(builder(), Blocks.BEDROCK));
|
||||
public static final Item SAND = register(new BlockItem(builder(), Blocks.SAND));
|
||||
@ -123,7 +155,7 @@ public final class Items {
|
||||
public static final Item RAW_IRON_BLOCK = register(new BlockItem(builder(), Blocks.RAW_IRON_BLOCK));
|
||||
public static final Item RAW_COPPER_BLOCK = register(new BlockItem(builder(), Blocks.RAW_COPPER_BLOCK));
|
||||
public static final Item RAW_GOLD_BLOCK = register(new BlockItem(builder(), Blocks.RAW_GOLD_BLOCK));
|
||||
public static final Item HEAVY_CORE = register(new BlockItem(builder().rarity(Rarity.EPIC), Blocks.HEAVY_CORE));
|
||||
public static final Item HEAVY_CORE = register(new BlockItem(builder(), Blocks.HEAVY_CORE));
|
||||
public static final Item AMETHYST_BLOCK = register(new BlockItem(builder(), Blocks.AMETHYST_BLOCK));
|
||||
public static final Item BUDDING_AMETHYST = register(new BlockItem(builder(), Blocks.BUDDING_AMETHYST));
|
||||
public static final Item IRON_BLOCK = register(new BlockItem(builder(), Blocks.IRON_BLOCK));
|
||||
@ -176,6 +208,7 @@ public final class Items {
|
||||
public static final Item JUNGLE_LOG = register(new BlockItem(builder(), Blocks.JUNGLE_LOG));
|
||||
public static final Item ACACIA_LOG = register(new BlockItem(builder(), Blocks.ACACIA_LOG));
|
||||
public static final Item CHERRY_LOG = register(new BlockItem(builder(), Blocks.CHERRY_LOG));
|
||||
public static final Item PALE_OAK_LOG = register(new BlockItem(builder(), Blocks.PALE_OAK_LOG));
|
||||
public static final Item DARK_OAK_LOG = register(new BlockItem(builder(), Blocks.DARK_OAK_LOG));
|
||||
public static final Item MANGROVE_LOG = register(new BlockItem(builder(), Blocks.MANGROVE_LOG));
|
||||
public static final Item MANGROVE_ROOTS = register(new BlockItem(builder(), Blocks.MANGROVE_ROOTS));
|
||||
@ -190,6 +223,7 @@ public final class Items {
|
||||
public static final Item STRIPPED_ACACIA_LOG = register(new BlockItem(builder(), Blocks.STRIPPED_ACACIA_LOG));
|
||||
public static final Item STRIPPED_CHERRY_LOG = register(new BlockItem(builder(), Blocks.STRIPPED_CHERRY_LOG));
|
||||
public static final Item STRIPPED_DARK_OAK_LOG = register(new BlockItem(builder(), Blocks.STRIPPED_DARK_OAK_LOG));
|
||||
public static final Item STRIPPED_PALE_OAK_LOG = register(new BlockItem(builder(), Blocks.STRIPPED_PALE_OAK_LOG));
|
||||
public static final Item STRIPPED_MANGROVE_LOG = register(new BlockItem(builder(), Blocks.STRIPPED_MANGROVE_LOG));
|
||||
public static final Item STRIPPED_CRIMSON_STEM = register(new BlockItem(builder(), Blocks.STRIPPED_CRIMSON_STEM));
|
||||
public static final Item STRIPPED_WARPED_STEM = register(new BlockItem(builder(), Blocks.STRIPPED_WARPED_STEM));
|
||||
@ -200,6 +234,7 @@ public final class Items {
|
||||
public static final Item STRIPPED_ACACIA_WOOD = register(new BlockItem(builder(), Blocks.STRIPPED_ACACIA_WOOD));
|
||||
public static final Item STRIPPED_CHERRY_WOOD = register(new BlockItem(builder(), Blocks.STRIPPED_CHERRY_WOOD));
|
||||
public static final Item STRIPPED_DARK_OAK_WOOD = register(new BlockItem(builder(), Blocks.STRIPPED_DARK_OAK_WOOD));
|
||||
public static final Item STRIPPED_PALE_OAK_WOOD = register(new BlockItem(builder(), Blocks.STRIPPED_PALE_OAK_WOOD));
|
||||
public static final Item STRIPPED_MANGROVE_WOOD = register(new BlockItem(builder(), Blocks.STRIPPED_MANGROVE_WOOD));
|
||||
public static final Item STRIPPED_CRIMSON_HYPHAE = register(new BlockItem(builder(), Blocks.STRIPPED_CRIMSON_HYPHAE));
|
||||
public static final Item STRIPPED_WARPED_HYPHAE = register(new BlockItem(builder(), Blocks.STRIPPED_WARPED_HYPHAE));
|
||||
@ -210,6 +245,7 @@ public final class Items {
|
||||
public static final Item JUNGLE_WOOD = register(new BlockItem(builder(), Blocks.JUNGLE_WOOD));
|
||||
public static final Item ACACIA_WOOD = register(new BlockItem(builder(), Blocks.ACACIA_WOOD));
|
||||
public static final Item CHERRY_WOOD = register(new BlockItem(builder(), Blocks.CHERRY_WOOD));
|
||||
public static final Item PALE_OAK_WOOD = register(new BlockItem(builder(), Blocks.PALE_OAK_WOOD));
|
||||
public static final Item DARK_OAK_WOOD = register(new BlockItem(builder(), Blocks.DARK_OAK_WOOD));
|
||||
public static final Item MANGROVE_WOOD = register(new BlockItem(builder(), Blocks.MANGROVE_WOOD));
|
||||
public static final Item CRIMSON_HYPHAE = register(new BlockItem(builder(), Blocks.CRIMSON_HYPHAE));
|
||||
@ -221,6 +257,7 @@ public final class Items {
|
||||
public static final Item ACACIA_LEAVES = register(new BlockItem(builder(), Blocks.ACACIA_LEAVES));
|
||||
public static final Item CHERRY_LEAVES = register(new BlockItem(builder(), Blocks.CHERRY_LEAVES));
|
||||
public static final Item DARK_OAK_LEAVES = register(new BlockItem(builder(), Blocks.DARK_OAK_LEAVES));
|
||||
public static final Item PALE_OAK_LEAVES = register(new BlockItem(builder(), Blocks.PALE_OAK_LEAVES));
|
||||
public static final Item MANGROVE_LEAVES = register(new BlockItem(builder(), Blocks.MANGROVE_LEAVES));
|
||||
public static final Item AZALEA_LEAVES = register(new BlockItem(builder(), Blocks.AZALEA_LEAVES));
|
||||
public static final Item FLOWERING_AZALEA_LEAVES = register(new BlockItem(builder(), Blocks.FLOWERING_AZALEA_LEAVES));
|
||||
@ -283,9 +320,12 @@ public final class Items {
|
||||
public static final Item TWISTING_VINES = register(new BlockItem(builder(), Blocks.TWISTING_VINES));
|
||||
public static final Item SUGAR_CANE = register(new BlockItem(builder(), Blocks.SUGAR_CANE));
|
||||
public static final Item KELP = register(new BlockItem(builder(), Blocks.KELP));
|
||||
public static final Item MOSS_CARPET = register(new BlockItem(builder(), Blocks.MOSS_CARPET));
|
||||
public static final Item PINK_PETALS = register(new BlockItem(builder(), Blocks.PINK_PETALS));
|
||||
public static final Item MOSS_CARPET = register(new BlockItem(builder(), Blocks.MOSS_CARPET));
|
||||
public static final Item MOSS_BLOCK = register(new BlockItem(builder(), Blocks.MOSS_BLOCK));
|
||||
public static final Item PALE_MOSS_CARPET = register(new BlockItem(builder(), Blocks.PALE_MOSS_CARPET));
|
||||
public static final Item PALE_HANGING_MOSS = register(new BlockItem(builder(), Blocks.PALE_HANGING_MOSS));
|
||||
public static final Item PALE_MOSS_BLOCK = register(new BlockItem(builder(), Blocks.PALE_MOSS_BLOCK));
|
||||
public static final Item HANGING_ROOTS = register(new BlockItem(builder(), Blocks.HANGING_ROOTS));
|
||||
public static final Item BIG_DRIPLEAF = register(new BlockItem(builder(), Blocks.BIG_DRIPLEAF, Blocks.BIG_DRIPLEAF_STEM));
|
||||
public static final Item SMALL_DRIPLEAF = register(new BlockItem(builder(), Blocks.SMALL_DRIPLEAF));
|
||||
@ -297,6 +337,7 @@ public final class Items {
|
||||
public static final Item ACACIA_SLAB = register(new BlockItem(builder(), Blocks.ACACIA_SLAB));
|
||||
public static final Item CHERRY_SLAB = register(new BlockItem(builder(), Blocks.CHERRY_SLAB));
|
||||
public static final Item DARK_OAK_SLAB = register(new BlockItem(builder(), Blocks.DARK_OAK_SLAB));
|
||||
public static final Item PALE_OAK_SLAB = register(new BlockItem(builder(), Blocks.PALE_OAK_SLAB));
|
||||
public static final Item MANGROVE_SLAB = register(new BlockItem(builder(), Blocks.MANGROVE_SLAB));
|
||||
public static final Item BAMBOO_SLAB = register(new BlockItem(builder(), Blocks.BAMBOO_SLAB));
|
||||
public static final Item BAMBOO_MOSAIC_SLAB = register(new BlockItem(builder(), Blocks.BAMBOO_MOSAIC_SLAB));
|
||||
@ -337,6 +378,7 @@ public final class Items {
|
||||
public static final Item PURPUR_PILLAR = register(new BlockItem(builder(), Blocks.PURPUR_PILLAR));
|
||||
public static final Item PURPUR_STAIRS = register(new BlockItem(builder(), Blocks.PURPUR_STAIRS));
|
||||
public static final Item SPAWNER = register(new BlockItem(builder(), Blocks.SPAWNER));
|
||||
public static final Item CREAKING_HEART = register(new BlockItem(builder(), Blocks.CREAKING_HEART));
|
||||
public static final Item CHEST = register(new BlockItem(builder(), Blocks.CHEST));
|
||||
public static final Item CRAFTING_TABLE = register(new BlockItem(builder(), Blocks.CRAFTING_TABLE));
|
||||
public static final Item FARMLAND = register(new BlockItem(builder(), Blocks.FARMLAND));
|
||||
@ -356,6 +398,7 @@ public final class Items {
|
||||
public static final Item ACACIA_FENCE = register(new BlockItem(builder(), Blocks.ACACIA_FENCE));
|
||||
public static final Item CHERRY_FENCE = register(new BlockItem(builder(), Blocks.CHERRY_FENCE));
|
||||
public static final Item DARK_OAK_FENCE = register(new BlockItem(builder(), Blocks.DARK_OAK_FENCE));
|
||||
public static final Item PALE_OAK_FENCE = register(new BlockItem(builder(), Blocks.PALE_OAK_FENCE));
|
||||
public static final Item MANGROVE_FENCE = register(new BlockItem(builder(), Blocks.MANGROVE_FENCE));
|
||||
public static final Item BAMBOO_FENCE = register(new BlockItem(builder(), Blocks.BAMBOO_FENCE));
|
||||
public static final Item CRIMSON_FENCE = register(new BlockItem(builder(), Blocks.CRIMSON_FENCE));
|
||||
@ -417,7 +460,7 @@ public final class Items {
|
||||
public static final Item END_PORTAL_FRAME = register(new BlockItem(builder(), Blocks.END_PORTAL_FRAME));
|
||||
public static final Item END_STONE = register(new BlockItem(builder(), Blocks.END_STONE));
|
||||
public static final Item END_STONE_BRICKS = register(new BlockItem(builder(), Blocks.END_STONE_BRICKS));
|
||||
public static final Item DRAGON_EGG = register(new BlockItem(builder().rarity(Rarity.EPIC), Blocks.DRAGON_EGG));
|
||||
public static final Item DRAGON_EGG = register(new BlockItem(builder(), Blocks.DRAGON_EGG));
|
||||
public static final Item SANDSTONE_STAIRS = register(new BlockItem(builder(), Blocks.SANDSTONE_STAIRS));
|
||||
public static final Item ENDER_CHEST = register(new BlockItem(builder(), Blocks.ENDER_CHEST));
|
||||
public static final Item EMERALD_BLOCK = register(new BlockItem(builder(), Blocks.EMERALD_BLOCK));
|
||||
@ -428,13 +471,14 @@ public final class Items {
|
||||
public static final Item ACACIA_STAIRS = register(new BlockItem(builder(), Blocks.ACACIA_STAIRS));
|
||||
public static final Item CHERRY_STAIRS = register(new BlockItem(builder(), Blocks.CHERRY_STAIRS));
|
||||
public static final Item DARK_OAK_STAIRS = register(new BlockItem(builder(), Blocks.DARK_OAK_STAIRS));
|
||||
public static final Item PALE_OAK_STAIRS = register(new BlockItem(builder(), Blocks.PALE_OAK_STAIRS));
|
||||
public static final Item MANGROVE_STAIRS = register(new BlockItem(builder(), Blocks.MANGROVE_STAIRS));
|
||||
public static final Item BAMBOO_STAIRS = register(new BlockItem(builder(), Blocks.BAMBOO_STAIRS));
|
||||
public static final Item BAMBOO_MOSAIC_STAIRS = register(new BlockItem(builder(), Blocks.BAMBOO_MOSAIC_STAIRS));
|
||||
public static final Item CRIMSON_STAIRS = register(new BlockItem(builder(), Blocks.CRIMSON_STAIRS));
|
||||
public static final Item WARPED_STAIRS = register(new BlockItem(builder(), Blocks.WARPED_STAIRS));
|
||||
public static final Item COMMAND_BLOCK = register(new BlockItem(builder().rarity(Rarity.EPIC), Blocks.COMMAND_BLOCK));
|
||||
public static final Item BEACON = register(new BlockItem(builder().rarity(Rarity.RARE), Blocks.BEACON));
|
||||
public static final Item COMMAND_BLOCK = register(new BlockItem(builder(), Blocks.COMMAND_BLOCK));
|
||||
public static final Item BEACON = register(new BlockItem(builder(), Blocks.BEACON));
|
||||
public static final Item COBBLESTONE_WALL = register(new BlockItem(builder(), Blocks.COBBLESTONE_WALL));
|
||||
public static final Item MOSSY_COBBLESTONE_WALL = register(new BlockItem(builder(), Blocks.MOSSY_COBBLESTONE_WALL));
|
||||
public static final Item BRICK_WALL = register(new BlockItem(builder(), Blocks.BRICK_WALL));
|
||||
@ -481,8 +525,8 @@ public final class Items {
|
||||
public static final Item GREEN_TERRACOTTA = register(new BlockItem(builder(), Blocks.GREEN_TERRACOTTA));
|
||||
public static final Item RED_TERRACOTTA = register(new BlockItem(builder(), Blocks.RED_TERRACOTTA));
|
||||
public static final Item BLACK_TERRACOTTA = register(new BlockItem(builder(), Blocks.BLACK_TERRACOTTA));
|
||||
public static final Item BARRIER = register(new BlockItem(builder().rarity(Rarity.EPIC), Blocks.BARRIER));
|
||||
public static final Item LIGHT = register(new BlockItem(builder().rarity(Rarity.EPIC), Blocks.LIGHT));
|
||||
public static final Item BARRIER = register(new BlockItem(builder(), Blocks.BARRIER));
|
||||
public static final Item LIGHT = register(new BlockItem(builder(), Blocks.LIGHT));
|
||||
public static final Item HAY_BLOCK = register(new BlockItem(builder(), Blocks.HAY_BLOCK));
|
||||
public static final Item WHITE_CARPET = register(new BlockItem(builder(), Blocks.WHITE_CARPET));
|
||||
public static final Item ORANGE_CARPET = register(new BlockItem(builder(), Blocks.ORANGE_CARPET));
|
||||
@ -552,14 +596,14 @@ public final class Items {
|
||||
public static final Item CHISELED_RED_SANDSTONE = register(new BlockItem(builder(), Blocks.CHISELED_RED_SANDSTONE));
|
||||
public static final Item CUT_RED_SANDSTONE = register(new BlockItem(builder(), Blocks.CUT_RED_SANDSTONE));
|
||||
public static final Item RED_SANDSTONE_STAIRS = register(new BlockItem(builder(), Blocks.RED_SANDSTONE_STAIRS));
|
||||
public static final Item REPEATING_COMMAND_BLOCK = register(new BlockItem(builder().rarity(Rarity.EPIC), Blocks.REPEATING_COMMAND_BLOCK));
|
||||
public static final Item CHAIN_COMMAND_BLOCK = register(new BlockItem(builder().rarity(Rarity.EPIC), Blocks.CHAIN_COMMAND_BLOCK));
|
||||
public static final Item REPEATING_COMMAND_BLOCK = register(new BlockItem(builder(), Blocks.REPEATING_COMMAND_BLOCK));
|
||||
public static final Item CHAIN_COMMAND_BLOCK = register(new BlockItem(builder(), Blocks.CHAIN_COMMAND_BLOCK));
|
||||
public static final Item MAGMA_BLOCK = register(new BlockItem(builder(), Blocks.MAGMA_BLOCK));
|
||||
public static final Item NETHER_WART_BLOCK = register(new BlockItem(builder(), Blocks.NETHER_WART_BLOCK));
|
||||
public static final Item WARPED_WART_BLOCK = register(new BlockItem(builder(), Blocks.WARPED_WART_BLOCK));
|
||||
public static final Item RED_NETHER_BRICKS = register(new BlockItem(builder(), Blocks.RED_NETHER_BRICKS));
|
||||
public static final Item BONE_BLOCK = register(new BlockItem(builder(), Blocks.BONE_BLOCK));
|
||||
public static final Item STRUCTURE_VOID = register(new BlockItem(builder().rarity(Rarity.EPIC), Blocks.STRUCTURE_VOID));
|
||||
public static final Item STRUCTURE_VOID = register(new BlockItem(builder(), Blocks.STRUCTURE_VOID));
|
||||
public static final Item SHULKER_BOX = register(new ShulkerBoxItem(builder().stackSize(1), Blocks.SHULKER_BOX));
|
||||
public static final Item WHITE_SHULKER_BOX = register(new ShulkerBoxItem(builder().stackSize(1), Blocks.WHITE_SHULKER_BOX));
|
||||
public static final Item ORANGE_SHULKER_BOX = register(new ShulkerBoxItem(builder().stackSize(1), Blocks.ORANGE_SHULKER_BOX));
|
||||
@ -658,7 +702,7 @@ public final class Items {
|
||||
public static final Item DEAD_FIRE_CORAL_FAN = register(new BlockItem(builder(), Blocks.DEAD_FIRE_CORAL_FAN, Blocks.DEAD_FIRE_CORAL_WALL_FAN));
|
||||
public static final Item DEAD_HORN_CORAL_FAN = register(new BlockItem(builder(), Blocks.DEAD_HORN_CORAL_FAN, Blocks.DEAD_HORN_CORAL_WALL_FAN));
|
||||
public static final Item BLUE_ICE = register(new BlockItem(builder(), Blocks.BLUE_ICE));
|
||||
public static final Item CONDUIT = register(new BlockItem(builder().rarity(Rarity.RARE), Blocks.CONDUIT));
|
||||
public static final Item CONDUIT = register(new BlockItem(builder(), Blocks.CONDUIT));
|
||||
public static final Item POLISHED_GRANITE_STAIRS = register(new BlockItem(builder(), Blocks.POLISHED_GRANITE_STAIRS));
|
||||
public static final Item SMOOTH_RED_SANDSTONE_STAIRS = register(new BlockItem(builder(), Blocks.SMOOTH_RED_SANDSTONE_STAIRS));
|
||||
public static final Item MOSSY_STONE_BRICK_STAIRS = register(new BlockItem(builder(), Blocks.MOSSY_STONE_BRICK_STAIRS));
|
||||
@ -729,6 +773,7 @@ public final class Items {
|
||||
public static final Item ACACIA_BUTTON = register(new BlockItem(builder(), Blocks.ACACIA_BUTTON));
|
||||
public static final Item CHERRY_BUTTON = register(new BlockItem(builder(), Blocks.CHERRY_BUTTON));
|
||||
public static final Item DARK_OAK_BUTTON = register(new BlockItem(builder(), Blocks.DARK_OAK_BUTTON));
|
||||
public static final Item PALE_OAK_BUTTON = register(new BlockItem(builder(), Blocks.PALE_OAK_BUTTON));
|
||||
public static final Item MANGROVE_BUTTON = register(new BlockItem(builder(), Blocks.MANGROVE_BUTTON));
|
||||
public static final Item BAMBOO_BUTTON = register(new BlockItem(builder(), Blocks.BAMBOO_BUTTON));
|
||||
public static final Item CRIMSON_BUTTON = register(new BlockItem(builder(), Blocks.CRIMSON_BUTTON));
|
||||
@ -744,6 +789,7 @@ public final class Items {
|
||||
public static final Item ACACIA_PRESSURE_PLATE = register(new BlockItem(builder(), Blocks.ACACIA_PRESSURE_PLATE));
|
||||
public static final Item CHERRY_PRESSURE_PLATE = register(new BlockItem(builder(), Blocks.CHERRY_PRESSURE_PLATE));
|
||||
public static final Item DARK_OAK_PRESSURE_PLATE = register(new BlockItem(builder(), Blocks.DARK_OAK_PRESSURE_PLATE));
|
||||
public static final Item PALE_OAK_PRESSURE_PLATE = register(new BlockItem(builder(), Blocks.PALE_OAK_PRESSURE_PLATE));
|
||||
public static final Item MANGROVE_PRESSURE_PLATE = register(new BlockItem(builder(), Blocks.MANGROVE_PRESSURE_PLATE));
|
||||
public static final Item BAMBOO_PRESSURE_PLATE = register(new BlockItem(builder(), Blocks.BAMBOO_PRESSURE_PLATE));
|
||||
public static final Item CRIMSON_PRESSURE_PLATE = register(new BlockItem(builder(), Blocks.CRIMSON_PRESSURE_PLATE));
|
||||
@ -756,6 +802,7 @@ public final class Items {
|
||||
public static final Item ACACIA_DOOR = register(new BlockItem(builder(), Blocks.ACACIA_DOOR));
|
||||
public static final Item CHERRY_DOOR = register(new BlockItem(builder(), Blocks.CHERRY_DOOR));
|
||||
public static final Item DARK_OAK_DOOR = register(new BlockItem(builder(), Blocks.DARK_OAK_DOOR));
|
||||
public static final Item PALE_OAK_DOOR = register(new BlockItem(builder(), Blocks.PALE_OAK_DOOR));
|
||||
public static final Item MANGROVE_DOOR = register(new BlockItem(builder(), Blocks.MANGROVE_DOOR));
|
||||
public static final Item BAMBOO_DOOR = register(new BlockItem(builder(), Blocks.BAMBOO_DOOR));
|
||||
public static final Item CRIMSON_DOOR = register(new BlockItem(builder(), Blocks.CRIMSON_DOOR));
|
||||
@ -776,6 +823,7 @@ public final class Items {
|
||||
public static final Item ACACIA_TRAPDOOR = register(new BlockItem(builder(), Blocks.ACACIA_TRAPDOOR));
|
||||
public static final Item CHERRY_TRAPDOOR = register(new BlockItem(builder(), Blocks.CHERRY_TRAPDOOR));
|
||||
public static final Item DARK_OAK_TRAPDOOR = register(new BlockItem(builder(), Blocks.DARK_OAK_TRAPDOOR));
|
||||
public static final Item PALE_OAK_TRAPDOOR = register(new BlockItem(builder(), Blocks.PALE_OAK_TRAPDOOR));
|
||||
public static final Item MANGROVE_TRAPDOOR = register(new BlockItem(builder(), Blocks.MANGROVE_TRAPDOOR));
|
||||
public static final Item BAMBOO_TRAPDOOR = register(new BlockItem(builder(), Blocks.BAMBOO_TRAPDOOR));
|
||||
public static final Item CRIMSON_TRAPDOOR = register(new BlockItem(builder(), Blocks.CRIMSON_TRAPDOOR));
|
||||
@ -795,6 +843,7 @@ public final class Items {
|
||||
public static final Item ACACIA_FENCE_GATE = register(new BlockItem(builder(), Blocks.ACACIA_FENCE_GATE));
|
||||
public static final Item CHERRY_FENCE_GATE = register(new BlockItem(builder(), Blocks.CHERRY_FENCE_GATE));
|
||||
public static final Item DARK_OAK_FENCE_GATE = register(new BlockItem(builder(), Blocks.DARK_OAK_FENCE_GATE));
|
||||
public static final Item PALE_OAK_FENCE_GATE = register(new BlockItem(builder(), Blocks.PALE_OAK_FENCE_GATE));
|
||||
public static final Item MANGROVE_FENCE_GATE = register(new BlockItem(builder(), Blocks.MANGROVE_FENCE_GATE));
|
||||
public static final Item BAMBOO_FENCE_GATE = register(new BlockItem(builder(), Blocks.BAMBOO_FENCE_GATE));
|
||||
public static final Item CRIMSON_FENCE_GATE = register(new BlockItem(builder(), Blocks.CRIMSON_FENCE_GATE));
|
||||
@ -811,7 +860,8 @@ public final class Items {
|
||||
public static final Item HOPPER_MINECART = register(new Item("hopper_minecart", builder().stackSize(1)));
|
||||
public static final Item CARROT_ON_A_STICK = register(new Item("carrot_on_a_stick", builder().stackSize(1).maxDamage(25)));
|
||||
public static final Item WARPED_FUNGUS_ON_A_STICK = register(new Item("warped_fungus_on_a_stick", builder().stackSize(1).maxDamage(100)));
|
||||
public static final Item ELYTRA = register(new ElytraItem("elytra", builder().stackSize(1).maxDamage(432).rarity(Rarity.UNCOMMON)));
|
||||
public static final Item PHANTOM_MEMBRANE = register(new Item("phantom_membrane", builder()));
|
||||
public static final Item ELYTRA = register(new ElytraItem("elytra", builder().stackSize(1).maxDamage(432)));
|
||||
public static final Item OAK_BOAT = register(new BoatItem("oak_boat", builder().stackSize(1)));
|
||||
public static final Item OAK_CHEST_BOAT = register(new BoatItem("oak_chest_boat", builder().stackSize(1)));
|
||||
public static final Item SPRUCE_BOAT = register(new BoatItem("spruce_boat", builder().stackSize(1)));
|
||||
@ -826,12 +876,14 @@ public final class Items {
|
||||
public static final Item CHERRY_CHEST_BOAT = register(new BoatItem("cherry_chest_boat", builder().stackSize(1)));
|
||||
public static final Item DARK_OAK_BOAT = register(new BoatItem("dark_oak_boat", builder().stackSize(1)));
|
||||
public static final Item DARK_OAK_CHEST_BOAT = register(new BoatItem("dark_oak_chest_boat", builder().stackSize(1)));
|
||||
public static final Item PALE_OAK_BOAT = register(new BoatItem("pale_oak_boat", builder().stackSize(1)));
|
||||
public static final Item PALE_OAK_CHEST_BOAT = register(new BoatItem("pale_oak_chest_boat", builder().stackSize(1)));
|
||||
public static final Item MANGROVE_BOAT = register(new BoatItem("mangrove_boat", builder().stackSize(1)));
|
||||
public static final Item MANGROVE_CHEST_BOAT = register(new BoatItem("mangrove_chest_boat", builder().stackSize(1)));
|
||||
public static final Item BAMBOO_RAFT = register(new BoatItem("bamboo_raft", builder().stackSize(1)));
|
||||
public static final Item BAMBOO_CHEST_RAFT = register(new BoatItem("bamboo_chest_raft", builder().stackSize(1)));
|
||||
public static final Item STRUCTURE_BLOCK = register(new BlockItem(builder().rarity(Rarity.EPIC), Blocks.STRUCTURE_BLOCK));
|
||||
public static final Item JIGSAW = register(new BlockItem(builder().rarity(Rarity.EPIC), Blocks.JIGSAW));
|
||||
public static final Item STRUCTURE_BLOCK = register(new BlockItem(builder(), Blocks.STRUCTURE_BLOCK));
|
||||
public static final Item JIGSAW = register(new BlockItem(builder(), Blocks.JIGSAW));
|
||||
public static final Item TURTLE_HELMET = register(new ArmorItem("turtle_helmet", ArmorMaterial.TURTLE, builder().stackSize(1).maxDamage(275)));
|
||||
public static final Item TURTLE_SCUTE = register(new Item("turtle_scute", builder()));
|
||||
public static final Item ARMADILLO_SCUTE = register(new Item("armadillo_scute", builder()));
|
||||
@ -922,8 +974,8 @@ public final class Items {
|
||||
public static final Item PORKCHOP = register(new Item("porkchop", builder()));
|
||||
public static final Item COOKED_PORKCHOP = register(new Item("cooked_porkchop", builder()));
|
||||
public static final Item PAINTING = register(new Item("painting", builder()));
|
||||
public static final Item GOLDEN_APPLE = register(new Item("golden_apple", builder().rarity(Rarity.RARE)));
|
||||
public static final Item ENCHANTED_GOLDEN_APPLE = register(new Item("enchanted_golden_apple", builder().rarity(Rarity.EPIC)));
|
||||
public static final Item GOLDEN_APPLE = register(new Item("golden_apple", builder()));
|
||||
public static final Item ENCHANTED_GOLDEN_APPLE = register(new Item("enchanted_golden_apple", builder()));
|
||||
public static final Item OAK_SIGN = register(new BlockItem(builder().stackSize(16), Blocks.OAK_SIGN, Blocks.OAK_WALL_SIGN));
|
||||
public static final Item SPRUCE_SIGN = register(new BlockItem(builder().stackSize(16), Blocks.SPRUCE_SIGN, Blocks.SPRUCE_WALL_SIGN));
|
||||
public static final Item BIRCH_SIGN = register(new BlockItem(builder().stackSize(16), Blocks.BIRCH_SIGN, Blocks.BIRCH_WALL_SIGN));
|
||||
@ -931,6 +983,7 @@ public final class Items {
|
||||
public static final Item ACACIA_SIGN = register(new BlockItem(builder().stackSize(16), Blocks.ACACIA_SIGN, Blocks.ACACIA_WALL_SIGN));
|
||||
public static final Item CHERRY_SIGN = register(new BlockItem(builder().stackSize(16), Blocks.CHERRY_SIGN, Blocks.CHERRY_WALL_SIGN));
|
||||
public static final Item DARK_OAK_SIGN = register(new BlockItem(builder().stackSize(16), Blocks.DARK_OAK_SIGN, Blocks.DARK_OAK_WALL_SIGN));
|
||||
public static final Item PALE_OAK_SIGN = register(new BlockItem(builder().stackSize(16), Blocks.PALE_OAK_SIGN, Blocks.PALE_OAK_WALL_SIGN));
|
||||
public static final Item MANGROVE_SIGN = register(new BlockItem(builder().stackSize(16), Blocks.MANGROVE_SIGN, Blocks.MANGROVE_WALL_SIGN));
|
||||
public static final Item BAMBOO_SIGN = register(new BlockItem(builder().stackSize(16), Blocks.BAMBOO_SIGN, Blocks.BAMBOO_WALL_SIGN));
|
||||
public static final Item CRIMSON_SIGN = register(new BlockItem(builder().stackSize(16), Blocks.CRIMSON_SIGN, Blocks.CRIMSON_WALL_SIGN));
|
||||
@ -942,6 +995,7 @@ public final class Items {
|
||||
public static final Item ACACIA_HANGING_SIGN = register(new BlockItem(builder().stackSize(16), Blocks.ACACIA_HANGING_SIGN, Blocks.ACACIA_WALL_HANGING_SIGN));
|
||||
public static final Item CHERRY_HANGING_SIGN = register(new BlockItem(builder().stackSize(16), Blocks.CHERRY_HANGING_SIGN, Blocks.CHERRY_WALL_HANGING_SIGN));
|
||||
public static final Item DARK_OAK_HANGING_SIGN = register(new BlockItem(builder().stackSize(16), Blocks.DARK_OAK_HANGING_SIGN, Blocks.DARK_OAK_WALL_HANGING_SIGN));
|
||||
public static final Item PALE_OAK_HANGING_SIGN = register(new BlockItem(builder().stackSize(16), Blocks.PALE_OAK_HANGING_SIGN, Blocks.PALE_OAK_WALL_HANGING_SIGN));
|
||||
public static final Item MANGROVE_HANGING_SIGN = register(new BlockItem(builder().stackSize(16), Blocks.MANGROVE_HANGING_SIGN, Blocks.MANGROVE_WALL_HANGING_SIGN));
|
||||
public static final Item BAMBOO_HANGING_SIGN = register(new BlockItem(builder().stackSize(16), Blocks.BAMBOO_HANGING_SIGN, Blocks.BAMBOO_WALL_HANGING_SIGN));
|
||||
public static final Item CRIMSON_HANGING_SIGN = register(new BlockItem(builder().stackSize(16), Blocks.CRIMSON_HANGING_SIGN, Blocks.CRIMSON_WALL_HANGING_SIGN));
|
||||
@ -969,6 +1023,22 @@ public final class Items {
|
||||
public static final Item COMPASS = register(new CompassItem("compass", builder()));
|
||||
public static final Item RECOVERY_COMPASS = register(new Item("recovery_compass", builder()));
|
||||
public static final Item BUNDLE = register(new Item("bundle", builder().stackSize(1)));
|
||||
public static final Item WHITE_BUNDLE = register(new Item("white_bundle", builder().stackSize(1)));
|
||||
public static final Item ORANGE_BUNDLE = register(new Item("orange_bundle", builder().stackSize(1)));
|
||||
public static final Item MAGENTA_BUNDLE = register(new Item("magenta_bundle", builder().stackSize(1)));
|
||||
public static final Item LIGHT_BLUE_BUNDLE = register(new Item("light_blue_bundle", builder().stackSize(1)));
|
||||
public static final Item YELLOW_BUNDLE = register(new Item("yellow_bundle", builder().stackSize(1)));
|
||||
public static final Item LIME_BUNDLE = register(new Item("lime_bundle", builder().stackSize(1)));
|
||||
public static final Item PINK_BUNDLE = register(new Item("pink_bundle", builder().stackSize(1)));
|
||||
public static final Item GRAY_BUNDLE = register(new Item("gray_bundle", builder().stackSize(1)));
|
||||
public static final Item LIGHT_GRAY_BUNDLE = register(new Item("light_gray_bundle", builder().stackSize(1)));
|
||||
public static final Item CYAN_BUNDLE = register(new Item("cyan_bundle", builder().stackSize(1)));
|
||||
public static final Item PURPLE_BUNDLE = register(new Item("purple_bundle", builder().stackSize(1)));
|
||||
public static final Item BLUE_BUNDLE = register(new Item("blue_bundle", builder().stackSize(1)));
|
||||
public static final Item BROWN_BUNDLE = register(new Item("brown_bundle", builder().stackSize(1)));
|
||||
public static final Item GREEN_BUNDLE = register(new Item("green_bundle", builder().stackSize(1)));
|
||||
public static final Item RED_BUNDLE = register(new Item("red_bundle", builder().stackSize(1)));
|
||||
public static final Item BLACK_BUNDLE = register(new Item("black_bundle", builder().stackSize(1)));
|
||||
public static final Item FISHING_ROD = register(new FishingRodItem("fishing_rod", builder().stackSize(1).maxDamage(64)));
|
||||
public static final Item CLOCK = register(new Item("clock", builder()));
|
||||
public static final Item SPYGLASS = register(new Item("spyglass", builder().stackSize(1)));
|
||||
@ -1036,14 +1106,14 @@ public final class Items {
|
||||
public static final Item GHAST_TEAR = register(new Item("ghast_tear", builder()));
|
||||
public static final Item GOLD_NUGGET = register(new Item("gold_nugget", builder()));
|
||||
public static final Item NETHER_WART = register(new BlockItem(builder(), Blocks.NETHER_WART));
|
||||
public static final Item POTION = register(new PotionItem("potion", builder().stackSize(1)));
|
||||
public static final Item GLASS_BOTTLE = register(new Item("glass_bottle", builder()));
|
||||
public static final Item POTION = register(new PotionItem("potion", builder().stackSize(1)));
|
||||
public static final Item SPIDER_EYE = register(new Item("spider_eye", builder()));
|
||||
public static final Item FERMENTED_SPIDER_EYE = register(new Item("fermented_spider_eye", builder()));
|
||||
public static final Item BLAZE_POWDER = register(new Item("blaze_powder", builder()));
|
||||
public static final Item MAGMA_CREAM = register(new Item("magma_cream", builder()));
|
||||
public static final Item BREWING_STAND = register(new BlockItem(builder(), Blocks.BREWING_STAND));
|
||||
public static final Item CAULDRON = register(new BlockItem(builder(), Blocks.CAULDRON, Blocks.WATER_CAULDRON, Blocks.POWDER_SNOW_CAULDRON, Blocks.LAVA_CAULDRON));
|
||||
public static final Item CAULDRON = register(new BlockItem(builder(), Blocks.CAULDRON, Blocks.LAVA_CAULDRON, Blocks.WATER_CAULDRON, Blocks.POWDER_SNOW_CAULDRON));
|
||||
public static final Item ENDER_EYE = register(new Item("ender_eye", builder()));
|
||||
public static final Item GLISTERING_MELON_SLICE = register(new Item("glistering_melon_slice", builder()));
|
||||
public static final Item ARMADILLO_SPAWN_EGG = register(new SpawnEggItem("armadillo_spawn_egg", builder()));
|
||||
@ -1122,16 +1192,18 @@ public final class Items {
|
||||
public static final Item WITHER_SKELETON_SPAWN_EGG = register(new SpawnEggItem("wither_skeleton_spawn_egg", builder()));
|
||||
public static final Item WOLF_SPAWN_EGG = register(new SpawnEggItem("wolf_spawn_egg", builder()));
|
||||
public static final Item ZOGLIN_SPAWN_EGG = register(new SpawnEggItem("zoglin_spawn_egg", builder()));
|
||||
public static final Item CREAKING_SPAWN_EGG = register(new SpawnEggItem("creaking_spawn_egg", builder()));
|
||||
public static final Item ZOMBIE_SPAWN_EGG = register(new SpawnEggItem("zombie_spawn_egg", builder()));
|
||||
public static final Item ZOMBIE_HORSE_SPAWN_EGG = register(new SpawnEggItem("zombie_horse_spawn_egg", builder()));
|
||||
public static final Item ZOMBIE_VILLAGER_SPAWN_EGG = register(new SpawnEggItem("zombie_villager_spawn_egg", builder()));
|
||||
public static final Item ZOMBIFIED_PIGLIN_SPAWN_EGG = register(new SpawnEggItem("zombified_piglin_spawn_egg", builder()));
|
||||
public static final Item EXPERIENCE_BOTTLE = register(new Item("experience_bottle", builder().rarity(Rarity.UNCOMMON)));
|
||||
public static final Item EXPERIENCE_BOTTLE = register(new Item("experience_bottle", builder()));
|
||||
public static final Item FIRE_CHARGE = register(new Item("fire_charge", builder()));
|
||||
public static final Item WIND_CHARGE = register(new Item("wind_charge", builder()));
|
||||
public static final Item WRITABLE_BOOK = register(new WritableBookItem("writable_book", builder().stackSize(1)));
|
||||
public static final Item WRITTEN_BOOK = register(new WrittenBookItem("written_book", builder().stackSize(16)));
|
||||
public static final Item MACE = register(new MaceItem("mace", builder().stackSize(1).maxDamage(500).rarity(Rarity.EPIC)));
|
||||
public static final Item BREEZE_ROD = register(new Item("breeze_rod", builder()));
|
||||
public static final Item MACE = register(new MaceItem("mace", builder().stackSize(1).maxDamage(500)));
|
||||
public static final Item ITEM_FRAME = register(new Item("item_frame", builder()));
|
||||
public static final Item GLOW_ITEM_FRAME = register(new Item("glow_item_frame", builder()));
|
||||
public static final Item FLOWER_POT = register(new BlockItem(builder(), Blocks.FLOWER_POT));
|
||||
@ -1141,18 +1213,18 @@ public final class Items {
|
||||
public static final Item POISONOUS_POTATO = register(new Item("poisonous_potato", builder()));
|
||||
public static final Item MAP = register(new MapItem("map", builder()));
|
||||
public static final Item GOLDEN_CARROT = register(new Item("golden_carrot", builder()));
|
||||
public static final Item SKELETON_SKULL = register(new BlockItem(builder().rarity(Rarity.UNCOMMON), Blocks.SKELETON_SKULL, Blocks.SKELETON_WALL_SKULL));
|
||||
public static final Item WITHER_SKELETON_SKULL = register(new BlockItem(builder().rarity(Rarity.UNCOMMON), Blocks.WITHER_SKELETON_SKULL, Blocks.WITHER_SKELETON_WALL_SKULL));
|
||||
public static final Item PLAYER_HEAD = register(new PlayerHeadItem(builder().rarity(Rarity.UNCOMMON), Blocks.PLAYER_HEAD, Blocks.PLAYER_WALL_HEAD));
|
||||
public static final Item ZOMBIE_HEAD = register(new BlockItem(builder().rarity(Rarity.UNCOMMON), Blocks.ZOMBIE_HEAD, Blocks.ZOMBIE_WALL_HEAD));
|
||||
public static final Item CREEPER_HEAD = register(new BlockItem(builder().rarity(Rarity.UNCOMMON), Blocks.CREEPER_HEAD, Blocks.CREEPER_WALL_HEAD));
|
||||
public static final Item DRAGON_HEAD = register(new BlockItem(builder().rarity(Rarity.UNCOMMON), Blocks.DRAGON_HEAD, Blocks.DRAGON_WALL_HEAD));
|
||||
public static final Item PIGLIN_HEAD = register(new BlockItem(builder().rarity(Rarity.UNCOMMON), Blocks.PIGLIN_HEAD, Blocks.PIGLIN_WALL_HEAD));
|
||||
public static final Item NETHER_STAR = register(new Item("nether_star", builder().rarity(Rarity.UNCOMMON)));
|
||||
public static final Item SKELETON_SKULL = register(new BlockItem(builder(), Blocks.SKELETON_SKULL, Blocks.SKELETON_WALL_SKULL));
|
||||
public static final Item WITHER_SKELETON_SKULL = register(new BlockItem(builder(), Blocks.WITHER_SKELETON_SKULL, Blocks.WITHER_SKELETON_WALL_SKULL));
|
||||
public static final Item PLAYER_HEAD = register(new PlayerHeadItem(builder(), Blocks.PLAYER_HEAD, Blocks.PLAYER_WALL_HEAD));
|
||||
public static final Item ZOMBIE_HEAD = register(new BlockItem(builder(), Blocks.ZOMBIE_HEAD, Blocks.ZOMBIE_WALL_HEAD));
|
||||
public static final Item CREEPER_HEAD = register(new BlockItem(builder(), Blocks.CREEPER_HEAD, Blocks.CREEPER_WALL_HEAD));
|
||||
public static final Item DRAGON_HEAD = register(new BlockItem(builder(), Blocks.DRAGON_HEAD, Blocks.DRAGON_WALL_HEAD));
|
||||
public static final Item PIGLIN_HEAD = register(new BlockItem(builder(), Blocks.PIGLIN_HEAD, Blocks.PIGLIN_WALL_HEAD));
|
||||
public static final Item NETHER_STAR = register(new Item("nether_star", builder()));
|
||||
public static final Item PUMPKIN_PIE = register(new Item("pumpkin_pie", builder()));
|
||||
public static final Item FIREWORK_ROCKET = register(new FireworkRocketItem("firework_rocket", builder()));
|
||||
public static final Item FIREWORK_STAR = register(new FireworkStarItem("firework_star", builder()));
|
||||
public static final Item ENCHANTED_BOOK = register(new EnchantedBookItem("enchanted_book", builder().stackSize(1).rarity(Rarity.UNCOMMON)));
|
||||
public static final Item ENCHANTED_BOOK = register(new EnchantedBookItem("enchanted_book", builder().stackSize(1)));
|
||||
public static final Item NETHER_BRICK = register(new Item("nether_brick", builder()));
|
||||
public static final Item PRISMARINE_SHARD = register(new Item("prismarine_shard", builder()));
|
||||
public static final Item PRISMARINE_CRYSTALS = register(new Item("prismarine_crystals", builder()));
|
||||
@ -1162,13 +1234,13 @@ public final class Items {
|
||||
public static final Item RABBIT_FOOT = register(new Item("rabbit_foot", builder()));
|
||||
public static final Item RABBIT_HIDE = register(new Item("rabbit_hide", builder()));
|
||||
public static final Item ARMOR_STAND = register(new Item("armor_stand", builder().stackSize(16)));
|
||||
public static final Item IRON_HORSE_ARMOR = register(new ArmorItem("iron_horse_armor", ArmorMaterial.IRON, builder().stackSize(1)));
|
||||
public static final Item GOLDEN_HORSE_ARMOR = register(new ArmorItem("golden_horse_armor", ArmorMaterial.GOLD, builder().stackSize(1)));
|
||||
public static final Item DIAMOND_HORSE_ARMOR = register(new ArmorItem("diamond_horse_armor", ArmorMaterial.DIAMOND, builder().stackSize(1)));
|
||||
public static final Item IRON_HORSE_ARMOR = register(new Item("iron_horse_armor", builder().stackSize(1)));
|
||||
public static final Item GOLDEN_HORSE_ARMOR = register(new Item("golden_horse_armor", builder().stackSize(1)));
|
||||
public static final Item DIAMOND_HORSE_ARMOR = register(new Item("diamond_horse_armor", builder().stackSize(1)));
|
||||
public static final Item LEATHER_HORSE_ARMOR = register(new DyeableArmorItem("leather_horse_armor", ArmorMaterial.LEATHER, builder().stackSize(1)));
|
||||
public static final Item LEAD = register(new Item("lead", builder()));
|
||||
public static final Item NAME_TAG = register(new Item("name_tag", builder()));
|
||||
public static final Item COMMAND_BLOCK_MINECART = register(new Item("command_block_minecart", builder().stackSize(1).rarity(Rarity.EPIC)));
|
||||
public static final Item COMMAND_BLOCK_MINECART = register(new Item("command_block_minecart", builder().stackSize(1)));
|
||||
public static final Item MUTTON = register(new Item("mutton", builder()));
|
||||
public static final Item COOKED_MUTTON = register(new Item("cooked_mutton", builder()));
|
||||
public static final Item WHITE_BANNER = register(new BannerItem(builder().stackSize(16), Blocks.WHITE_BANNER, Blocks.WHITE_WALL_BANNER));
|
||||
@ -1187,7 +1259,7 @@ public final class Items {
|
||||
public static final Item GREEN_BANNER = register(new BannerItem(builder().stackSize(16), Blocks.GREEN_BANNER, Blocks.GREEN_WALL_BANNER));
|
||||
public static final Item RED_BANNER = register(new BannerItem(builder().stackSize(16), Blocks.RED_BANNER, Blocks.RED_WALL_BANNER));
|
||||
public static final Item BLACK_BANNER = register(new BannerItem(builder().stackSize(16), Blocks.BLACK_BANNER, Blocks.BLACK_WALL_BANNER));
|
||||
public static final Item END_CRYSTAL = register(new Item("end_crystal", builder().rarity(Rarity.RARE)));
|
||||
public static final Item END_CRYSTAL = register(new Item("end_crystal", builder()));
|
||||
public static final Item CHORUS_FRUIT = register(new Item("chorus_fruit", builder()));
|
||||
public static final Item POPPED_CHORUS_FRUIT = register(new Item("popped_chorus_fruit", builder()));
|
||||
public static final Item TORCHFLOWER_SEEDS = register(new BlockItem("torchflower_seeds", builder(), Blocks.TORCHFLOWER_CROP));
|
||||
@ -1195,52 +1267,53 @@ public final class Items {
|
||||
public static final Item BEETROOT = register(new Item("beetroot", builder()));
|
||||
public static final Item BEETROOT_SEEDS = register(new BlockItem("beetroot_seeds", builder(), Blocks.BEETROOTS));
|
||||
public static final Item BEETROOT_SOUP = register(new Item("beetroot_soup", builder().stackSize(1)));
|
||||
public static final Item DRAGON_BREATH = register(new Item("dragon_breath", builder().rarity(Rarity.UNCOMMON)));
|
||||
public static final Item DRAGON_BREATH = register(new Item("dragon_breath", builder()));
|
||||
public static final Item SPLASH_POTION = register(new PotionItem("splash_potion", builder().stackSize(1)));
|
||||
public static final Item SPECTRAL_ARROW = register(new Item("spectral_arrow", builder()));
|
||||
public static final Item TIPPED_ARROW = register(new TippedArrowItem("tipped_arrow", builder()));
|
||||
public static final Item LINGERING_POTION = register(new PotionItem("lingering_potion", builder().stackSize(1)));
|
||||
public static final Item SHIELD = register(new ShieldItem("shield", builder().stackSize(1).maxDamage(336)));
|
||||
public static final Item TOTEM_OF_UNDYING = register(new Item("totem_of_undying", builder().stackSize(1).rarity(Rarity.UNCOMMON)));
|
||||
public static final Item TOTEM_OF_UNDYING = register(new Item("totem_of_undying", builder().stackSize(1)));
|
||||
public static final Item SHULKER_SHELL = register(new Item("shulker_shell", builder()));
|
||||
public static final Item IRON_NUGGET = register(new Item("iron_nugget", builder()));
|
||||
public static final Item KNOWLEDGE_BOOK = register(new Item("knowledge_book", builder().stackSize(1).rarity(Rarity.EPIC)));
|
||||
public static final Item DEBUG_STICK = register(new Item("debug_stick", builder().stackSize(1).rarity(Rarity.EPIC).glint(true)));
|
||||
public static final Item MUSIC_DISC_13 = register(new Item("music_disc_13", builder().stackSize(1).rarity(Rarity.RARE)));
|
||||
public static final Item MUSIC_DISC_CAT = register(new Item("music_disc_cat", builder().stackSize(1).rarity(Rarity.RARE)));
|
||||
public static final Item MUSIC_DISC_BLOCKS = register(new Item("music_disc_blocks", builder().stackSize(1).rarity(Rarity.RARE)));
|
||||
public static final Item MUSIC_DISC_CHIRP = register(new Item("music_disc_chirp", builder().stackSize(1).rarity(Rarity.RARE)));
|
||||
public static final Item MUSIC_DISC_CREATOR = register(new Item("music_disc_creator", builder().stackSize(1).rarity(Rarity.RARE)));
|
||||
public static final Item MUSIC_DISC_CREATOR_MUSIC_BOX = register(new Item("music_disc_creator_music_box", builder().stackSize(1).rarity(Rarity.RARE)));
|
||||
public static final Item MUSIC_DISC_FAR = register(new Item("music_disc_far", builder().stackSize(1).rarity(Rarity.RARE)));
|
||||
public static final Item MUSIC_DISC_MALL = register(new Item("music_disc_mall", builder().stackSize(1).rarity(Rarity.RARE)));
|
||||
public static final Item MUSIC_DISC_MELLOHI = register(new Item("music_disc_mellohi", builder().stackSize(1).rarity(Rarity.RARE)));
|
||||
public static final Item MUSIC_DISC_STAL = register(new Item("music_disc_stal", builder().stackSize(1).rarity(Rarity.RARE)));
|
||||
public static final Item MUSIC_DISC_STRAD = register(new Item("music_disc_strad", builder().stackSize(1).rarity(Rarity.RARE)));
|
||||
public static final Item MUSIC_DISC_WARD = register(new Item("music_disc_ward", builder().stackSize(1).rarity(Rarity.RARE)));
|
||||
public static final Item MUSIC_DISC_11 = register(new Item("music_disc_11", builder().stackSize(1).rarity(Rarity.RARE)));
|
||||
public static final Item MUSIC_DISC_WAIT = register(new Item("music_disc_wait", builder().stackSize(1).rarity(Rarity.RARE)));
|
||||
public static final Item MUSIC_DISC_OTHERSIDE = register(new Item("music_disc_otherside", builder().stackSize(1).rarity(Rarity.RARE)));
|
||||
public static final Item MUSIC_DISC_RELIC = register(new Item("music_disc_relic", builder().stackSize(1).rarity(Rarity.RARE)));
|
||||
public static final Item MUSIC_DISC_5 = register(new Item("music_disc_5", builder().stackSize(1).rarity(Rarity.RARE)));
|
||||
public static final Item MUSIC_DISC_PIGSTEP = register(new Item("music_disc_pigstep", builder().stackSize(1).rarity(Rarity.RARE)));
|
||||
public static final Item MUSIC_DISC_PRECIPICE = register(new Item("music_disc_precipice", builder().stackSize(1).rarity(Rarity.RARE)));
|
||||
public static final Item KNOWLEDGE_BOOK = register(new Item("knowledge_book", builder().stackSize(1)));
|
||||
public static final Item DEBUG_STICK = register(new Item("debug_stick", builder().stackSize(1)));
|
||||
public static final Item MUSIC_DISC_13 = register(new Item("music_disc_13", builder().stackSize(1)));
|
||||
public static final Item MUSIC_DISC_CAT = register(new Item("music_disc_cat", builder().stackSize(1)));
|
||||
public static final Item MUSIC_DISC_BLOCKS = register(new Item("music_disc_blocks", builder().stackSize(1)));
|
||||
public static final Item MUSIC_DISC_CHIRP = register(new Item("music_disc_chirp", builder().stackSize(1)));
|
||||
public static final Item MUSIC_DISC_CREATOR = register(new Item("music_disc_creator", builder().stackSize(1)));
|
||||
public static final Item MUSIC_DISC_CREATOR_MUSIC_BOX = register(new Item("music_disc_creator_music_box", builder().stackSize(1)));
|
||||
public static final Item MUSIC_DISC_FAR = register(new Item("music_disc_far", builder().stackSize(1)));
|
||||
public static final Item MUSIC_DISC_MALL = register(new Item("music_disc_mall", builder().stackSize(1)));
|
||||
public static final Item MUSIC_DISC_MELLOHI = register(new Item("music_disc_mellohi", builder().stackSize(1)));
|
||||
public static final Item MUSIC_DISC_STAL = register(new Item("music_disc_stal", builder().stackSize(1)));
|
||||
public static final Item MUSIC_DISC_STRAD = register(new Item("music_disc_strad", builder().stackSize(1)));
|
||||
public static final Item MUSIC_DISC_WARD = register(new Item("music_disc_ward", builder().stackSize(1)));
|
||||
public static final Item MUSIC_DISC_11 = register(new Item("music_disc_11", builder().stackSize(1)));
|
||||
public static final Item MUSIC_DISC_WAIT = register(new Item("music_disc_wait", builder().stackSize(1)));
|
||||
public static final Item MUSIC_DISC_OTHERSIDE = register(new Item("music_disc_otherside", builder().stackSize(1)));
|
||||
public static final Item MUSIC_DISC_RELIC = register(new Item("music_disc_relic", builder().stackSize(1)));
|
||||
public static final Item MUSIC_DISC_5 = register(new Item("music_disc_5", builder().stackSize(1)));
|
||||
public static final Item MUSIC_DISC_PIGSTEP = register(new Item("music_disc_pigstep", builder().stackSize(1)));
|
||||
public static final Item MUSIC_DISC_PRECIPICE = register(new Item("music_disc_precipice", builder().stackSize(1)));
|
||||
public static final Item DISC_FRAGMENT_5 = register(new Item("disc_fragment_5", builder()));
|
||||
public static final Item TRIDENT = register(new Item("trident", builder().stackSize(1).maxDamage(250).attackDamage(9.0).rarity(Rarity.EPIC)));
|
||||
public static final Item PHANTOM_MEMBRANE = register(new Item("phantom_membrane", builder()));
|
||||
public static final Item TRIDENT = register(new Item("trident", builder().stackSize(1).maxDamage(250).attackDamage(9.0)));
|
||||
public static final Item NAUTILUS_SHELL = register(new Item("nautilus_shell", builder()));
|
||||
public static final Item HEART_OF_THE_SEA = register(new Item("heart_of_the_sea", builder().rarity(Rarity.UNCOMMON)));
|
||||
public static final Item HEART_OF_THE_SEA = register(new Item("heart_of_the_sea", builder()));
|
||||
public static final Item CROSSBOW = register(new CrossbowItem("crossbow", builder().stackSize(1).maxDamage(465)));
|
||||
public static final Item SUSPICIOUS_STEW = register(new Item("suspicious_stew", builder().stackSize(1)));
|
||||
public static final Item LOOM = register(new BlockItem(builder(), Blocks.LOOM));
|
||||
public static final Item FLOWER_BANNER_PATTERN = register(new Item("flower_banner_pattern", builder().stackSize(1)));
|
||||
public static final Item CREEPER_BANNER_PATTERN = register(new Item("creeper_banner_pattern", builder().stackSize(1).rarity(Rarity.UNCOMMON)));
|
||||
public static final Item SKULL_BANNER_PATTERN = register(new Item("skull_banner_pattern", builder().stackSize(1).rarity(Rarity.UNCOMMON)));
|
||||
public static final Item MOJANG_BANNER_PATTERN = register(new Item("mojang_banner_pattern", builder().stackSize(1).rarity(Rarity.EPIC)));
|
||||
public static final Item CREEPER_BANNER_PATTERN = register(new Item("creeper_banner_pattern", builder().stackSize(1)));
|
||||
public static final Item SKULL_BANNER_PATTERN = register(new Item("skull_banner_pattern", builder().stackSize(1)));
|
||||
public static final Item MOJANG_BANNER_PATTERN = register(new Item("mojang_banner_pattern", builder().stackSize(1)));
|
||||
public static final Item GLOBE_BANNER_PATTERN = register(new Item("globe_banner_pattern", builder().stackSize(1)));
|
||||
public static final Item PIGLIN_BANNER_PATTERN = register(new Item("piglin_banner_pattern", builder().stackSize(1).rarity(Rarity.UNCOMMON)));
|
||||
public static final Item FLOW_BANNER_PATTERN = register(new Item("flow_banner_pattern", builder().stackSize(1).rarity(Rarity.RARE)));
|
||||
public static final Item GUSTER_BANNER_PATTERN = register(new Item("guster_banner_pattern", builder().stackSize(1).rarity(Rarity.RARE)));
|
||||
public static final Item PIGLIN_BANNER_PATTERN = register(new Item("piglin_banner_pattern", builder().stackSize(1)));
|
||||
public static final Item FLOW_BANNER_PATTERN = register(new Item("flow_banner_pattern", builder().stackSize(1)));
|
||||
public static final Item GUSTER_BANNER_PATTERN = register(new Item("guster_banner_pattern", builder().stackSize(1)));
|
||||
public static final Item FIELD_MASONED_BANNER_PATTERN = register(new Item("field_masoned_banner_pattern", builder().stackSize(1)));
|
||||
public static final Item BORDURE_INDENTED_BANNER_PATTERN = register(new Item("bordure_indented_banner_pattern", builder().stackSize(1)));
|
||||
public static final Item GOAT_HORN = register(new GoatHornItem("goat_horn", builder().stackSize(1)));
|
||||
public static final Item COMPOSTER = register(new BlockItem(builder(), Blocks.COMPOSTER));
|
||||
public static final Item BARREL = register(new BlockItem(builder(), Blocks.BARREL));
|
||||
@ -1369,8 +1442,7 @@ public final class Items {
|
||||
public static final Item TRIAL_KEY = register(new Item("trial_key", builder()));
|
||||
public static final Item OMINOUS_TRIAL_KEY = register(new Item("ominous_trial_key", builder()));
|
||||
public static final Item VAULT = register(new BlockItem(builder(), Blocks.VAULT));
|
||||
public static final Item OMINOUS_BOTTLE = register(new OminousBottleItem("ominous_bottle", builder()));
|
||||
public static final Item BREEZE_ROD = register(new Item("breeze_rod", builder()));
|
||||
public static final Item OMINOUS_BOTTLE = register(new Item("ominous_bottle", builder()));
|
||||
|
||||
public static final int AIR_ID = AIR.javaId();
|
||||
|
||||
|
@ -25,52 +25,47 @@
|
||||
|
||||
package org.geysermc.geyser.item.enchantment;
|
||||
|
||||
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;
|
||||
import org.geysermc.geyser.inventory.item.BedrockEnchantment;
|
||||
import org.geysermc.geyser.item.Items;
|
||||
import org.geysermc.geyser.item.type.Item;
|
||||
import org.geysermc.geyser.registry.Registries;
|
||||
import org.geysermc.geyser.session.cache.registry.JavaRegistries;
|
||||
import org.geysermc.geyser.session.cache.registry.RegistryEntryContext;
|
||||
import org.geysermc.geyser.session.cache.tags.GeyserHolderSet;
|
||||
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 java.util.function.ToIntFunction;
|
||||
|
||||
/**
|
||||
* @param description only populated if {@link #bedrockEnchantment()} is not null.
|
||||
* @param description only populated if {@link #bedrockEnchantment()} is null.
|
||||
* @param anvilCost also as a rarity multiplier
|
||||
*/
|
||||
public record Enchantment(String identifier,
|
||||
Set<EnchantmentComponent> effects,
|
||||
HolderSet supportedItems,
|
||||
GeyserHolderSet<Item> supportedItems,
|
||||
int maxLevel,
|
||||
String description,
|
||||
int anvilCost,
|
||||
HolderSet exclusiveSet,
|
||||
GeyserHolderSet<Enchantment> exclusiveSet,
|
||||
@Nullable BedrockEnchantment bedrockEnchantment) {
|
||||
|
||||
public static Enchantment read(RegistryEntryContext context) {
|
||||
NbtMap data = context.data();
|
||||
Set<EnchantmentComponent> effects = readEnchantmentComponents(data.getCompound("effects"));
|
||||
|
||||
HolderSet supportedItems = readHolderSet(data.get("supported_items"), itemId -> Registries.JAVA_ITEM_IDENTIFIERS.getOrDefault(itemId.asString(), Items.AIR).javaId());
|
||||
GeyserHolderSet<Item> supportedItems = GeyserHolderSet.readHolderSet(context.session(), JavaRegistries.ITEM, data.get("supported_items"), itemId -> Registries.JAVA_ITEM_IDENTIFIERS.getOrDefault(itemId.asString(), Items.AIR).javaId());
|
||||
|
||||
int maxLevel = data.getInt("max_level");
|
||||
int anvilCost = data.getInt("anvil_cost");
|
||||
|
||||
HolderSet exclusiveSet = readHolderSet(data.getOrDefault("exclusive_set", null), context::getNetworkId);
|
||||
GeyserHolderSet<Enchantment> exclusiveSet = GeyserHolderSet.readHolderSet(context.session(), JavaRegistries.ENCHANTMENT, data.get("exclusive_set"), context::getNetworkId);
|
||||
|
||||
BedrockEnchantment bedrockEnchantment = BedrockEnchantment.getByJavaIdentifier(context.id().asString());
|
||||
|
||||
// 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(context.session(), data) : null;
|
||||
|
||||
return new Enchantment(context.id().asString(), effects, supportedItems, maxLevel,
|
||||
@ -86,24 +81,4 @@ public record Enchantment(String identifier,
|
||||
}
|
||||
return Set.copyOf(components); // Also ensures any empty sets are consolidated
|
||||
}
|
||||
|
||||
// TODO holder set util?
|
||||
private static HolderSet readHolderSet(@Nullable Object holderSet, ToIntFunction<Key> keyIdMapping) {
|
||||
if (holderSet == null) {
|
||||
return new HolderSet(IntArrays.EMPTY_ARRAY);
|
||||
}
|
||||
|
||||
if (holderSet instanceof String stringTag) {
|
||||
// Tag
|
||||
if (stringTag.startsWith("#")) {
|
||||
return new HolderSet(MinecraftKey.key(stringTag.substring(1))); // Remove '#' at beginning that indicates tag
|
||||
} else {
|
||||
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).mapToInt(keyIdMapping).toArray());
|
||||
}
|
||||
throw new IllegalArgumentException("Holder set must either be a tag, a string ID or a list of string IDs");
|
||||
}
|
||||
}
|
||||
|
@ -32,6 +32,7 @@ import org.geysermc.geyser.inventory.item.Potion;
|
||||
import org.geysermc.geyser.item.Items;
|
||||
import org.geysermc.geyser.registry.type.ItemMapping;
|
||||
import org.geysermc.geyser.registry.type.ItemMappings;
|
||||
import org.geysermc.geyser.session.GeyserSession;
|
||||
import org.geysermc.mcprotocollib.protocol.data.game.item.component.DataComponentType;
|
||||
import org.geysermc.mcprotocollib.protocol.data.game.item.component.PotionContents;
|
||||
|
||||
@ -41,9 +42,9 @@ public class ArrowItem extends Item {
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NonNull GeyserItemStack translateToJava(@NonNull ItemData itemData, @NonNull ItemMapping mapping, @NonNull ItemMappings mappings) {
|
||||
public @NonNull GeyserItemStack translateToJava(GeyserSession session, @NonNull ItemData itemData, @NonNull ItemMapping mapping, @NonNull ItemMappings mappings) {
|
||||
Potion potion = Potion.getByTippedArrowDamage(itemData.getDamage());
|
||||
GeyserItemStack itemStack = super.translateToJava(itemData, mapping, mappings);
|
||||
GeyserItemStack itemStack = super.translateToJava(session, itemData, mapping, mappings);
|
||||
if (potion != null) {
|
||||
itemStack = Items.TIPPED_ARROW.newItemStack(itemStack.getAmount(), itemStack.getComponents());
|
||||
PotionContents contents = potion.toComponent();
|
||||
|
@ -43,11 +43,11 @@ public class CompassItem extends Item {
|
||||
}
|
||||
|
||||
@Override
|
||||
public ItemData.Builder translateToBedrock(int count, DataComponents components, ItemMapping mapping, ItemMappings mappings) {
|
||||
public ItemData.Builder translateToBedrock(GeyserSession session, int count, DataComponents components, ItemMapping mapping, ItemMappings mappings) {
|
||||
if (isLodestoneCompass(components)) {
|
||||
return super.translateToBedrock(count, components, mappings.getLodestoneCompass(), mappings);
|
||||
return super.translateToBedrock(session, count, components, mappings.getLodestoneCompass(), mappings);
|
||||
}
|
||||
return super.translateToBedrock(count, components, mapping, mappings);
|
||||
return super.translateToBedrock(session, count, components, mapping, mappings);
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -78,12 +78,12 @@ public class CompassItem extends Item {
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NonNull GeyserItemStack translateToJava(@NonNull ItemData itemData, @NonNull ItemMapping mapping, @NonNull ItemMappings mappings) {
|
||||
public @NonNull GeyserItemStack translateToJava(GeyserSession session, @NonNull ItemData itemData, @NonNull ItemMapping mapping, @NonNull ItemMappings mappings) {
|
||||
if (mapping.getBedrockIdentifier().equals("minecraft:lodestone_compass")) {
|
||||
// Revert the entry back to the compass
|
||||
mapping = mappings.getStoredItems().compass();
|
||||
}
|
||||
|
||||
return super.translateToJava(itemData, mapping, mappings);
|
||||
return super.translateToJava(session, itemData, mapping, mappings);
|
||||
}
|
||||
}
|
||||
|
@ -28,6 +28,7 @@ package org.geysermc.geyser.item.type;
|
||||
import org.cloudburstmc.protocol.bedrock.data.inventory.ItemData;
|
||||
import org.geysermc.geyser.registry.type.ItemMapping;
|
||||
import org.geysermc.geyser.registry.type.ItemMappings;
|
||||
import org.geysermc.geyser.session.GeyserSession;
|
||||
import org.geysermc.mcprotocollib.protocol.data.game.item.component.DataComponentType;
|
||||
import org.geysermc.mcprotocollib.protocol.data.game.item.component.DataComponents;
|
||||
|
||||
@ -37,8 +38,8 @@ public class FilledMapItem extends MapItem {
|
||||
}
|
||||
|
||||
@Override
|
||||
public ItemData.Builder translateToBedrock(int count, DataComponents components, ItemMapping mapping, ItemMappings mappings) {
|
||||
ItemData.Builder builder = super.translateToBedrock(count, components, mapping, mappings);
|
||||
public ItemData.Builder translateToBedrock(GeyserSession session, int count, DataComponents components, ItemMapping mapping, ItemMappings mappings) {
|
||||
ItemData.Builder builder = super.translateToBedrock(session, count, components, mapping, mappings);
|
||||
if (components == null) {
|
||||
// This is a fallback for maps with no nbt (Change added back in June 2020; is it needed in 2023?)
|
||||
//return builder.tag(NbtMap.builder().putInt("map", 0).build()); TODO if this is *still* broken, let's move it to translateComponentsToBedrock
|
||||
|
@ -28,8 +28,11 @@ package org.geysermc.geyser.item.type;
|
||||
import org.checkerframework.checker.nullness.qual.NonNull;
|
||||
import org.cloudburstmc.protocol.bedrock.data.inventory.ItemData;
|
||||
import org.geysermc.geyser.inventory.GeyserItemStack;
|
||||
import org.geysermc.geyser.inventory.item.GeyserInstrument;
|
||||
import org.geysermc.geyser.registry.type.ItemMapping;
|
||||
import org.geysermc.geyser.registry.type.ItemMappings;
|
||||
import org.geysermc.geyser.session.GeyserSession;
|
||||
import org.geysermc.geyser.translator.item.BedrockItemBuilder;
|
||||
import org.geysermc.mcprotocollib.protocol.data.game.Holder;
|
||||
import org.geysermc.mcprotocollib.protocol.data.game.item.component.DataComponentType;
|
||||
import org.geysermc.mcprotocollib.protocol.data.game.item.component.DataComponents;
|
||||
@ -41,24 +44,45 @@ public class GoatHornItem extends Item {
|
||||
}
|
||||
|
||||
@Override
|
||||
public ItemData.Builder translateToBedrock(int count, DataComponents components, ItemMapping mapping, ItemMappings mappings) {
|
||||
ItemData.Builder builder = super.translateToBedrock(count, components, mapping, mappings);
|
||||
public ItemData.Builder translateToBedrock(GeyserSession session, int count, DataComponents components, ItemMapping mapping, ItemMappings mappings) {
|
||||
ItemData.Builder builder = super.translateToBedrock(session, count, components, mapping, mappings);
|
||||
if (components == null) {
|
||||
return builder;
|
||||
}
|
||||
Holder<Instrument> instrument = components.get(DataComponentType.INSTRUMENT);
|
||||
if (instrument != null && instrument.isId()) {
|
||||
builder.damage(instrument.id());
|
||||
|
||||
Holder<Instrument> holder = components.get(DataComponentType.INSTRUMENT);
|
||||
if (holder != null) {
|
||||
GeyserInstrument instrument = GeyserInstrument.fromHolder(session, holder);
|
||||
int bedrockId = instrument.bedrockId();
|
||||
if (bedrockId >= 0) {
|
||||
builder.damage(bedrockId);
|
||||
}
|
||||
}
|
||||
|
||||
return builder;
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NonNull GeyserItemStack translateToJava(@NonNull ItemData itemData, @NonNull ItemMapping mapping, @NonNull ItemMappings mappings) {
|
||||
GeyserItemStack itemStack = super.translateToJava(itemData, mapping, mappings);
|
||||
public void translateComponentsToBedrock(@NonNull GeyserSession session, @NonNull DataComponents components, @NonNull BedrockItemBuilder builder) {
|
||||
super.translateComponentsToBedrock(session, components, builder);
|
||||
|
||||
Holder<Instrument> holder = components.get(DataComponentType.INSTRUMENT);
|
||||
if (holder != null && components.get(DataComponentType.HIDE_TOOLTIP) == null
|
||||
&& components.get(DataComponentType.HIDE_ADDITIONAL_TOOLTIP) == null) {
|
||||
GeyserInstrument instrument = GeyserInstrument.fromHolder(session, holder);
|
||||
if (instrument.bedrockInstrument() == null) {
|
||||
builder.getOrCreateLore().add(instrument.description());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NonNull GeyserItemStack translateToJava(GeyserSession session, @NonNull ItemData itemData, @NonNull ItemMapping mapping, @NonNull ItemMappings mappings) {
|
||||
GeyserItemStack itemStack = super.translateToJava(session, itemData, mapping, mappings);
|
||||
|
||||
int damage = itemData.getDamage();
|
||||
itemStack.getOrCreateComponents().put(DataComponentType.INSTRUMENT, Holder.ofId(damage));
|
||||
// This could cause an issue since -1 is returned for non-vanilla goat horns
|
||||
itemStack.getOrCreateComponents().put(DataComponentType.INSTRUMENT, Holder.ofId(GeyserInstrument.bedrockIdToJava(session, damage)));
|
||||
|
||||
return itemStack;
|
||||
}
|
||||
|
@ -115,7 +115,7 @@ public class Item {
|
||||
|
||||
/* Translation methods to Bedrock and back */
|
||||
|
||||
public ItemData.Builder translateToBedrock(int count, DataComponents components, ItemMapping mapping, ItemMappings mappings) {
|
||||
public ItemData.Builder translateToBedrock(GeyserSession session, int count, DataComponents components, ItemMapping mapping, ItemMappings mappings) {
|
||||
if (this == Items.AIR || count <= 0) {
|
||||
// Return, essentially, air
|
||||
return ItemData.builder();
|
||||
@ -130,7 +130,7 @@ public class Item {
|
||||
return builder;
|
||||
}
|
||||
|
||||
public @NonNull GeyserItemStack translateToJava(@NonNull ItemData itemData, @NonNull ItemMapping mapping, @NonNull ItemMappings mappings) {
|
||||
public @NonNull GeyserItemStack translateToJava(GeyserSession session, @NonNull ItemData itemData, @NonNull ItemMapping mapping, @NonNull ItemMappings mappings) {
|
||||
return GeyserItemStack.of(javaId, itemData.getCount());
|
||||
}
|
||||
|
||||
|
@ -31,6 +31,7 @@ import org.cloudburstmc.protocol.bedrock.data.inventory.ItemData;
|
||||
import org.geysermc.geyser.inventory.GeyserItemStack;
|
||||
import org.geysermc.geyser.registry.type.ItemMapping;
|
||||
import org.geysermc.geyser.registry.type.ItemMappings;
|
||||
import org.geysermc.geyser.session.GeyserSession;
|
||||
import org.geysermc.mcprotocollib.protocol.data.game.item.component.DataComponentType;
|
||||
import org.geysermc.mcprotocollib.protocol.data.game.item.component.DataComponents;
|
||||
|
||||
@ -40,8 +41,8 @@ public class OminousBottleItem extends Item {
|
||||
}
|
||||
|
||||
@Override
|
||||
public ItemData.Builder translateToBedrock(int count, @Nullable DataComponents components, ItemMapping mapping, ItemMappings mappings) {
|
||||
var builder = super.translateToBedrock(count, components, mapping, mappings);
|
||||
public ItemData.Builder translateToBedrock(GeyserSession session, int count, @Nullable DataComponents components, ItemMapping mapping, ItemMappings mappings) {
|
||||
var builder = super.translateToBedrock(session, count, components, mapping, mappings);
|
||||
if (components == null) {
|
||||
// Level 1 ominous bottle is null components - Java 1.21.
|
||||
return builder;
|
||||
@ -54,9 +55,9 @@ public class OminousBottleItem extends Item {
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NonNull GeyserItemStack translateToJava(@NonNull ItemData itemData, @NonNull ItemMapping mapping, @NonNull ItemMappings mappings) {
|
||||
public @NonNull GeyserItemStack translateToJava(GeyserSession session, @NonNull ItemData itemData, @NonNull ItemMapping mapping, @NonNull ItemMappings mappings) {
|
||||
// This item can be pulled from the creative inventory with amplifiers.
|
||||
GeyserItemStack itemStack = super.translateToJava(itemData, mapping, mappings);
|
||||
GeyserItemStack itemStack = super.translateToJava(session, itemData, mapping, mappings);
|
||||
int damage = itemData.getDamage();
|
||||
if (damage == 0) {
|
||||
return itemStack;
|
||||
|
@ -33,6 +33,7 @@ import org.geysermc.geyser.inventory.GeyserItemStack;
|
||||
import org.geysermc.geyser.inventory.item.Potion;
|
||||
import org.geysermc.geyser.registry.type.ItemMapping;
|
||||
import org.geysermc.geyser.registry.type.ItemMappings;
|
||||
import org.geysermc.geyser.session.GeyserSession;
|
||||
import org.geysermc.geyser.translator.item.CustomItemTranslator;
|
||||
import org.geysermc.mcprotocollib.protocol.data.game.item.component.DataComponentType;
|
||||
import org.geysermc.mcprotocollib.protocol.data.game.item.component.DataComponents;
|
||||
@ -44,8 +45,8 @@ public class PotionItem extends Item {
|
||||
}
|
||||
|
||||
@Override
|
||||
public ItemData.Builder translateToBedrock(int count, DataComponents components, ItemMapping mapping, ItemMappings mappings) {
|
||||
if (components == null) return super.translateToBedrock(count, components, mapping, mappings);
|
||||
public ItemData.Builder translateToBedrock(GeyserSession session, int count, DataComponents components, ItemMapping mapping, ItemMappings mappings) {
|
||||
if (components == null) return super.translateToBedrock(session, count, components, mapping, mappings);
|
||||
PotionContents potionContents = components.get(DataComponentType.POTION_CONTENTS);
|
||||
if (potionContents != null) {
|
||||
ItemDefinition customItemDefinition = CustomItemTranslator.getCustomItem(components, mapping);
|
||||
@ -64,13 +65,13 @@ public class PotionItem extends Item {
|
||||
.count(count);
|
||||
}
|
||||
}
|
||||
return super.translateToBedrock(count, components, mapping, mappings);
|
||||
return super.translateToBedrock(session, count, components, mapping, mappings);
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NonNull GeyserItemStack translateToJava(@NonNull ItemData itemData, @NonNull ItemMapping mapping, @NonNull ItemMappings mappings) {
|
||||
public @NonNull GeyserItemStack translateToJava(GeyserSession session, @NonNull ItemData itemData, @NonNull ItemMapping mapping, @NonNull ItemMappings mappings) {
|
||||
Potion potion = Potion.getByBedrockId(itemData.getDamage());
|
||||
GeyserItemStack itemStack = super.translateToJava(itemData, mapping, mappings);
|
||||
GeyserItemStack itemStack = super.translateToJava(session, itemData, mapping, mappings);
|
||||
if (potion != null) {
|
||||
itemStack.getOrCreateComponents().put(DataComponentType.POTION_CONTENTS, potion.toComponent());
|
||||
}
|
||||
|
@ -30,6 +30,7 @@ import org.geysermc.geyser.GeyserImpl;
|
||||
import org.geysermc.geyser.inventory.item.Potion;
|
||||
import org.geysermc.geyser.registry.type.ItemMapping;
|
||||
import org.geysermc.geyser.registry.type.ItemMappings;
|
||||
import org.geysermc.geyser.session.GeyserSession;
|
||||
import org.geysermc.mcprotocollib.protocol.data.game.item.component.DataComponentType;
|
||||
import org.geysermc.mcprotocollib.protocol.data.game.item.component.DataComponents;
|
||||
import org.geysermc.mcprotocollib.protocol.data.game.item.component.PotionContents;
|
||||
@ -40,7 +41,7 @@ public class TippedArrowItem extends ArrowItem {
|
||||
}
|
||||
|
||||
@Override
|
||||
public ItemData.Builder translateToBedrock(int count, DataComponents components, ItemMapping mapping, ItemMappings mappings) {
|
||||
public ItemData.Builder translateToBedrock(GeyserSession session, int count, DataComponents components, ItemMapping mapping, ItemMappings mappings) {
|
||||
if (components != null) {
|
||||
PotionContents potionContents = components.get(DataComponentType.POTION_CONTENTS);
|
||||
if (potionContents != null) {
|
||||
@ -54,6 +55,6 @@ public class TippedArrowItem extends ArrowItem {
|
||||
GeyserImpl.getInstance().getLogger().debug("Unknown Java potion (tipped arrow): " + potionContents.getPotionId());
|
||||
}
|
||||
}
|
||||
return super.translateToBedrock(count, components, mapping, mappings);
|
||||
return super.translateToBedrock(session, count, components, mapping, mappings);
|
||||
}
|
||||
}
|
||||
|
@ -26,24 +26,15 @@
|
||||
package org.geysermc.geyser.level;
|
||||
|
||||
import org.cloudburstmc.nbt.NbtMap;
|
||||
import org.geysermc.geyser.GeyserImpl;
|
||||
import org.geysermc.geyser.session.cache.registry.RegistryEntryContext;
|
||||
import org.geysermc.geyser.translator.text.MessageTranslator;
|
||||
import org.geysermc.geyser.util.SoundUtils;
|
||||
|
||||
public record JukeboxSong(String soundEvent, String description) {
|
||||
|
||||
public static JukeboxSong read(RegistryEntryContext context) {
|
||||
NbtMap data = context.data();
|
||||
Object soundEventObject = data.get("sound_event");
|
||||
String soundEvent;
|
||||
if (soundEventObject instanceof NbtMap map) {
|
||||
soundEvent = map.getString("sound_id");
|
||||
} else if (soundEventObject instanceof String string) {
|
||||
soundEvent = string;
|
||||
} else {
|
||||
soundEvent = "";
|
||||
GeyserImpl.getInstance().getLogger().debug("Sound event for " + context.id() + " was of an unexpected type! Expected string or NBT map, got " + soundEventObject);
|
||||
}
|
||||
String soundEvent = SoundUtils.readSoundEvent(data, "jukebox song " + context.id());
|
||||
String description = MessageTranslator.deserializeDescription(context.session(), data);
|
||||
return new JukeboxSong(soundEvent, description);
|
||||
}
|
||||
|
Datei-Diff unterdrückt, da er zu groß ist
Diff laden
@ -47,6 +47,7 @@ public final class Properties {
|
||||
public static final BooleanProperty INVERTED = BooleanProperty.create("inverted");
|
||||
public static final BooleanProperty IN_WALL = BooleanProperty.create("in_wall");
|
||||
public static final BooleanProperty LIT = BooleanProperty.create("lit");
|
||||
public static final BooleanProperty TIP = BooleanProperty.create("tip");
|
||||
public static final BooleanProperty LOCKED = BooleanProperty.create("locked");
|
||||
public static final BooleanProperty OCCUPIED = BooleanProperty.create("occupied");
|
||||
public static final BooleanProperty OPEN = BooleanProperty.create("open");
|
||||
@ -142,5 +143,6 @@ public final class Properties {
|
||||
public static final BooleanProperty CRAFTING = BooleanProperty.create("crafting");
|
||||
public static final BasicEnumProperty TRIAL_SPAWNER_STATE = BasicEnumProperty.create("trial_spawner_state", "inactive", "waiting_for_players", "active", "waiting_for_reward_ejection", "ejecting_reward", "cooldown");
|
||||
public static final BasicEnumProperty VAULT_STATE = BasicEnumProperty.create("vault_state", "inactive", "active", "unlocking", "ejecting");
|
||||
public static final BasicEnumProperty CREAKING = BasicEnumProperty.create("creaking", "disabled", "dormant", "active");
|
||||
public static final BooleanProperty OMINOUS = BooleanProperty.create("ominous");
|
||||
}
|
||||
|
@ -27,6 +27,7 @@ package org.geysermc.geyser.level.physics;
|
||||
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
import net.kyori.adventure.util.TriState;
|
||||
import org.checkerframework.checker.nullness.qual.Nullable;
|
||||
import org.cloudburstmc.math.GenericMath;
|
||||
import org.cloudburstmc.math.vector.Vector3d;
|
||||
@ -153,11 +154,10 @@ public class CollisionManager {
|
||||
* the two versions. Will also send corrected movement packets back to Bedrock if they collide with pistons.
|
||||
*
|
||||
* @param bedrockPosition the current Bedrock position of the client
|
||||
* @param onGround whether the Bedrock player is on the ground
|
||||
* @param teleported whether the Bedrock player has teleported to a new position. If true, movement correction is skipped.
|
||||
* @return the position to send to the Java server, or null to cancel sending the packet
|
||||
*/
|
||||
public @Nullable Vector3d adjustBedrockPosition(Vector3f bedrockPosition, boolean onGround, boolean teleported) {
|
||||
public @Nullable CollisionResult adjustBedrockPosition(Vector3f bedrockPosition, boolean teleported) {
|
||||
PistonCache pistonCache = session.getPistonCache();
|
||||
// Bedrock clients tend to fall off of honey blocks, so we need to teleport them to the new position
|
||||
if (pistonCache.isPlayerAttachedToHoney()) {
|
||||
@ -176,7 +176,7 @@ public class CollisionManager {
|
||||
playerBoundingBox.setMiddleY(position.getY() + playerBoundingBox.getSizeY() / 2);
|
||||
playerBoundingBox.setMiddleZ(position.getZ());
|
||||
|
||||
return playerBoundingBox.getBottomCenter();
|
||||
return new CollisionResult(playerBoundingBox.getBottomCenter(), TriState.NOT_SET);
|
||||
}
|
||||
|
||||
Vector3d startingPos = playerBoundingBox.getBottomCenter();
|
||||
@ -198,13 +198,13 @@ public class CollisionManager {
|
||||
|
||||
position = playerBoundingBox.getBottomCenter();
|
||||
|
||||
boolean newOnGround = adjustedMovement.getY() != movement.getY() && movement.getY() < 0 || onGround;
|
||||
boolean onGround = (adjustedMovement.getY() != movement.getY() && movement.getY() < 0) || isOnGround();
|
||||
// Send corrected position to Bedrock if they differ by too much to prevent de-syncs
|
||||
if (onGround != newOnGround || movement.distanceSquared(adjustedMovement) > INCORRECT_MOVEMENT_THRESHOLD) {
|
||||
if (movement.distanceSquared(adjustedMovement) > INCORRECT_MOVEMENT_THRESHOLD) {
|
||||
PlayerEntity playerEntity = session.getPlayerEntity();
|
||||
// Client will dismount if on a vehicle
|
||||
if (playerEntity.getVehicle() == null && pistonCache.getPlayerMotion().equals(Vector3f.ZERO) && !pistonCache.isPlayerSlimeCollision()) {
|
||||
playerEntity.moveAbsolute(position.toFloat(), playerEntity.getYaw(), playerEntity.getPitch(), playerEntity.getHeadYaw(), newOnGround, true);
|
||||
playerEntity.moveAbsolute(position.toFloat(), playerEntity.getYaw(), playerEntity.getPitch(), playerEntity.getHeadYaw(), onGround, true);
|
||||
}
|
||||
}
|
||||
|
||||
@ -213,7 +213,7 @@ public class CollisionManager {
|
||||
position = Vector3d.from(position.getX(), Double.parseDouble(DECIMAL_FORMAT.format(position.getY())), position.getZ());
|
||||
}
|
||||
|
||||
return position;
|
||||
return new CollisionResult(position, TriState.byBoolean(onGround));
|
||||
}
|
||||
|
||||
// TODO: This makes the player look upwards for some reason, rotation values must be wrong
|
||||
@ -415,44 +415,38 @@ public class CollisionManager {
|
||||
return BlockUtils.getCollision(blockId);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return true if the block located at the player's floor position plus 1 would intersect with the player,
|
||||
* were they not sneaking
|
||||
*/
|
||||
public boolean mustPlayerSneakHere() {
|
||||
return checkPose(EntityDefinitions.PLAYER.height());
|
||||
}
|
||||
|
||||
/**
|
||||
* @return true if the block located at the player's floor position plus 1 would intersect with the player,
|
||||
* were they not crawling
|
||||
*/
|
||||
public boolean mustPlayerCrawlHere() {
|
||||
return checkPose(PlayerEntity.SNEAKING_POSE_HEIGHT);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param height check and see if this height is invalid in the current player position
|
||||
*/
|
||||
private boolean checkPose(float height) {
|
||||
Vector3i position = session.getPlayerEntity().getPosition().toInt();
|
||||
BlockCollision collision = BlockUtils.getCollisionAt(session, position);
|
||||
if (collision != null) {
|
||||
// Determine, if the player's bounding box *were* at full height, if it would intersect with the block
|
||||
// at the current location.
|
||||
double originalY = playerBoundingBox.getMiddleY();
|
||||
double originalHeight = playerBoundingBox.getSizeY();
|
||||
double standingY = originalY - (originalHeight / 2.0) + (height / 2.0);
|
||||
|
||||
playerBoundingBox.setSizeY(EntityDefinitions.PLAYER.height());
|
||||
playerBoundingBox.setMiddleY(standingY);
|
||||
boolean result = collision.checkIntersection(position, playerBoundingBox);
|
||||
result |= session.getPistonCache().checkCollision(position, playerBoundingBox);
|
||||
playerBoundingBox.setSizeY(originalHeight);
|
||||
playerBoundingBox.setMiddleY(originalY);
|
||||
return result;
|
||||
private boolean isOnGround() {
|
||||
// Someone smarter than me at collisions plz check this.
|
||||
Vector3d bottomCenter = playerBoundingBox.getBottomCenter();
|
||||
Vector3i groundPos = Vector3i.from(bottomCenter.getX(), bottomCenter.getY() - 1, bottomCenter.getZ());
|
||||
BlockCollision collision = BlockUtils.getCollisionAt(session, groundPos);
|
||||
if (collision == null) {
|
||||
return false; // Probably air.
|
||||
}
|
||||
return false;
|
||||
|
||||
// Hack to not check below the player
|
||||
playerBoundingBox.setSizeY(playerBoundingBox.getSizeY() - 0.001);
|
||||
playerBoundingBox.setMiddleY(playerBoundingBox.getMiddleY() + 0.002);
|
||||
|
||||
boolean intersected = collision.checkIntersection(groundPos.getX(), groundPos.getY(), groundPos.getZ(), playerBoundingBox);
|
||||
|
||||
playerBoundingBox.setSizeY(playerBoundingBox.getSizeY() + 0.001);
|
||||
playerBoundingBox.setMiddleY(playerBoundingBox.getMiddleY() - 0.002);
|
||||
|
||||
boolean result;
|
||||
if (intersected) {
|
||||
result = true;
|
||||
} else {
|
||||
// Hack to check slightly below the player
|
||||
playerBoundingBox.setSizeY(playerBoundingBox.getSizeY() + 0.001);
|
||||
playerBoundingBox.setMiddleY(playerBoundingBox.getMiddleY() - 0.002);
|
||||
|
||||
result = collision.checkIntersection(groundPos.getX(), groundPos.getY(), groundPos.getZ(), playerBoundingBox);
|
||||
|
||||
playerBoundingBox.setSizeY(playerBoundingBox.getSizeY() - 0.001);
|
||||
playerBoundingBox.setMiddleY(playerBoundingBox.getMiddleY() + 0.002);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -23,11 +23,13 @@
|
||||
* @link https://github.com/GeyserMC/Geyser
|
||||
*/
|
||||
|
||||
package org.geysermc.geyser.util;
|
||||
package org.geysermc.geyser.level.physics;
|
||||
|
||||
import net.kyori.adventure.util.TriState;
|
||||
import org.cloudburstmc.math.vector.Vector3d;
|
||||
|
||||
/**
|
||||
* Represents anything that could be tracked like a enum, without also creating a name and enum-wide array.
|
||||
* Holds the result of a collision check.
|
||||
*/
|
||||
public interface Ordered {
|
||||
int ordinal();
|
||||
public record CollisionResult(Vector3d correctedMovement, TriState onGround) {
|
||||
}
|
@ -31,11 +31,13 @@ import org.cloudburstmc.protocol.bedrock.codec.BedrockCodecHelper;
|
||||
import org.cloudburstmc.protocol.bedrock.codec.BedrockPacketSerializer;
|
||||
import org.cloudburstmc.protocol.bedrock.codec.v291.serializer.MobArmorEquipmentSerializer_v291;
|
||||
import org.cloudburstmc.protocol.bedrock.codec.v291.serializer.MobEquipmentSerializer_v291;
|
||||
import org.cloudburstmc.protocol.bedrock.codec.v291.serializer.MoveEntityAbsoluteSerializer_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.v390.serializer.PlayerSkinSerializer_v390;
|
||||
import org.cloudburstmc.protocol.bedrock.codec.v407.serializer.InventoryContentSerializer_v407;
|
||||
import org.cloudburstmc.protocol.bedrock.codec.v407.serializer.InventorySlotSerializer_v407;
|
||||
import org.cloudburstmc.protocol.bedrock.codec.v419.serializer.MovePlayerSerializer_v419;
|
||||
import org.cloudburstmc.protocol.bedrock.codec.v486.serializer.BossEventSerializer_v486;
|
||||
import org.cloudburstmc.protocol.bedrock.codec.v557.serializer.SetEntityDataSerializer_v557;
|
||||
import org.cloudburstmc.protocol.bedrock.codec.v662.serializer.SetEntityMotionSerializer_v662;
|
||||
@ -67,15 +69,18 @@ import org.cloudburstmc.protocol.bedrock.packet.MapCreateLockedCopyPacket;
|
||||
import org.cloudburstmc.protocol.bedrock.packet.MapInfoRequestPacket;
|
||||
import org.cloudburstmc.protocol.bedrock.packet.MobArmorEquipmentPacket;
|
||||
import org.cloudburstmc.protocol.bedrock.packet.MobEquipmentPacket;
|
||||
import org.cloudburstmc.protocol.bedrock.packet.MoveEntityAbsolutePacket;
|
||||
import org.cloudburstmc.protocol.bedrock.packet.MovePlayerPacket;
|
||||
import org.cloudburstmc.protocol.bedrock.packet.MultiplayerSettingsPacket;
|
||||
import org.cloudburstmc.protocol.bedrock.packet.NpcRequestPacket;
|
||||
import org.cloudburstmc.protocol.bedrock.packet.PhotoInfoRequestPacket;
|
||||
import org.cloudburstmc.protocol.bedrock.packet.PhotoTransferPacket;
|
||||
import org.cloudburstmc.protocol.bedrock.packet.PlayerAuthInputPacket;
|
||||
import org.cloudburstmc.protocol.bedrock.packet.PlayerHotbarPacket;
|
||||
import org.cloudburstmc.protocol.bedrock.packet.PlayerInputPacket;
|
||||
import org.cloudburstmc.protocol.bedrock.packet.PlayerSkinPacket;
|
||||
import org.cloudburstmc.protocol.bedrock.packet.PurchaseReceiptPacket;
|
||||
import org.cloudburstmc.protocol.bedrock.packet.RefreshEntitlementsPacket;
|
||||
import org.cloudburstmc.protocol.bedrock.packet.RiderJumpPacket;
|
||||
import org.cloudburstmc.protocol.bedrock.packet.ScriptMessagePacket;
|
||||
import org.cloudburstmc.protocol.bedrock.packet.SetEntityDataPacket;
|
||||
import org.cloudburstmc.protocol.bedrock.packet.SetEntityLinkPacket;
|
||||
@ -190,6 +195,20 @@ class CodecProcessor {
|
||||
}
|
||||
};
|
||||
|
||||
private static final BedrockPacketSerializer<MovePlayerPacket> MOVE_PLAYER_SERIALIZER = new MovePlayerSerializer_v419() {
|
||||
@Override
|
||||
public void deserialize(ByteBuf buffer, BedrockCodecHelper helper, MovePlayerPacket packet) {
|
||||
throw new IllegalArgumentException("Client cannot send MovePlayerPacket in server-auth movement environment!");
|
||||
}
|
||||
};
|
||||
|
||||
private static final BedrockPacketSerializer<MoveEntityAbsolutePacket> MOVE_ENTITY_SERIALIZER = new MoveEntityAbsoluteSerializer_v291() {
|
||||
@Override
|
||||
public void deserialize(ByteBuf buffer, BedrockCodecHelper helper, MoveEntityAbsolutePacket packet) {
|
||||
throw new IllegalArgumentException("Client cannot send MoveEntityAbsolutePacket in server-auth movement environment!");
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Serializer that does nothing when trying to deserialize BossEventPacket since it is not used from the client.
|
||||
*/
|
||||
@ -318,7 +337,6 @@ class CodecProcessor {
|
||||
.updateSerializer(ClientCheatAbilityPacket.class, ILLEGAL_SERIALIZER)
|
||||
.updateSerializer(CraftingEventPacket.class, ILLEGAL_SERIALIZER)
|
||||
// Illegal unusued serverbound packets that relate to unused features
|
||||
.updateSerializer(PlayerAuthInputPacket.class, ILLEGAL_SERIALIZER)
|
||||
.updateSerializer(ClientCacheBlobStatusPacket.class, ILLEGAL_SERIALIZER)
|
||||
.updateSerializer(SubClientLoginPacket.class, ILLEGAL_SERIALIZER)
|
||||
.updateSerializer(SubChunkRequestPacket.class, ILLEGAL_SERIALIZER)
|
||||
@ -334,6 +352,10 @@ class CodecProcessor {
|
||||
// Illegal when serverbound due to Geyser specific setup
|
||||
.updateSerializer(InventoryContentPacket.class, inventoryContentSerializer)
|
||||
.updateSerializer(InventorySlotPacket.class, inventorySlotSerializer)
|
||||
.updateSerializer(MovePlayerPacket.class, MOVE_PLAYER_SERIALIZER)
|
||||
.updateSerializer(MoveEntityAbsolutePacket.class, MOVE_ENTITY_SERIALIZER)
|
||||
.updateSerializer(RiderJumpPacket.class, ILLEGAL_SERIALIZER)
|
||||
.updateSerializer(PlayerInputPacket.class, ILLEGAL_SERIALIZER)
|
||||
// Ignored only when serverbound
|
||||
.updateSerializer(BossEventPacket.class, BOSS_EVENT_SERIALIZER)
|
||||
.updateSerializer(MobArmorEquipmentPacket.class, is712OrAbove ? MOB_ARMOR_EQUIPMENT_SERIALIZER_V712 : MOB_ARMOR_EQUIPMENT_SERIALIZER_V291)
|
||||
|
@ -26,6 +26,7 @@
|
||||
package org.geysermc.geyser.network;
|
||||
|
||||
import io.netty.buffer.Unpooled;
|
||||
import org.cloudburstmc.math.vector.Vector2f;
|
||||
import org.cloudburstmc.protocol.bedrock.BedrockDisconnectReasons;
|
||||
import org.cloudburstmc.protocol.bedrock.codec.BedrockCodec;
|
||||
import org.cloudburstmc.protocol.bedrock.codec.compat.BedrockCompat;
|
||||
@ -38,9 +39,9 @@ import org.cloudburstmc.protocol.bedrock.netty.codec.compression.ZlibCompression
|
||||
import org.cloudburstmc.protocol.bedrock.packet.BedrockPacket;
|
||||
import org.cloudburstmc.protocol.bedrock.packet.LoginPacket;
|
||||
import org.cloudburstmc.protocol.bedrock.packet.ModalFormResponsePacket;
|
||||
import org.cloudburstmc.protocol.bedrock.packet.MovePlayerPacket;
|
||||
import org.cloudburstmc.protocol.bedrock.packet.NetworkSettingsPacket;
|
||||
import org.cloudburstmc.protocol.bedrock.packet.PlayStatusPacket;
|
||||
import org.cloudburstmc.protocol.bedrock.packet.PlayerAuthInputPacket;
|
||||
import org.cloudburstmc.protocol.bedrock.packet.RequestNetworkSettingsPacket;
|
||||
import org.cloudburstmc.protocol.bedrock.packet.ResourcePackChunkDataPacket;
|
||||
import org.cloudburstmc.protocol.bedrock.packet.ResourcePackChunkRequestPacket;
|
||||
@ -290,8 +291,9 @@ public class UpstreamPacketHandler extends LoggingPacketHandler {
|
||||
}
|
||||
|
||||
@Override
|
||||
public PacketSignal handle(MovePlayerPacket packet) {
|
||||
if (session.isLoggingIn()) {
|
||||
public PacketSignal handle(PlayerAuthInputPacket packet) {
|
||||
// This doesn't catch rotation, but for a niche case I don't exactly want to cache rotation...
|
||||
if (session.isLoggingIn() && !packet.getMotion().equals(Vector2f.ZERO)) {
|
||||
SetTitlePacket titlePacket = new SetTitlePacket();
|
||||
titlePacket.setType(SetTitlePacket.Type.ACTIONBAR);
|
||||
titlePacket.setText(GeyserLocale.getPlayerLocaleString("geyser.auth.login.wait", session.locale()));
|
||||
|
@ -27,6 +27,7 @@ package org.geysermc.geyser.registry;
|
||||
|
||||
import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap;
|
||||
import it.unimi.dsi.fastutil.objects.Object2IntMap;
|
||||
import it.unimi.dsi.fastutil.objects.Object2ObjectMap;
|
||||
import it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap;
|
||||
import org.cloudburstmc.nbt.NbtMap;
|
||||
import org.cloudburstmc.nbt.NbtMapBuilder;
|
||||
@ -42,13 +43,13 @@ import org.geysermc.geyser.registry.loader.BlockEntityRegistryLoader;
|
||||
import org.geysermc.geyser.registry.loader.ParticleTypesRegistryLoader;
|
||||
import org.geysermc.geyser.registry.loader.PotionMixRegistryLoader;
|
||||
import org.geysermc.geyser.registry.loader.ProviderRegistryLoader;
|
||||
import org.geysermc.geyser.registry.loader.RecipeRegistryLoader;
|
||||
import org.geysermc.geyser.registry.loader.RegistryLoaders;
|
||||
import org.geysermc.geyser.registry.loader.SoundEventsRegistryLoader;
|
||||
import org.geysermc.geyser.registry.loader.SoundRegistryLoader;
|
||||
import org.geysermc.geyser.registry.loader.SoundTranslatorRegistryLoader;
|
||||
import org.geysermc.geyser.registry.populator.ItemRegistryPopulator;
|
||||
import org.geysermc.geyser.registry.populator.PacketRegistryPopulator;
|
||||
import org.geysermc.geyser.registry.populator.TagRegistryPopulator;
|
||||
import org.geysermc.geyser.registry.provider.ProviderSupplier;
|
||||
import org.geysermc.geyser.registry.type.ItemMappings;
|
||||
import org.geysermc.geyser.registry.type.ParticleMapping;
|
||||
@ -62,13 +63,11 @@ import org.geysermc.mcprotocollib.protocol.data.game.entity.type.EntityType;
|
||||
import org.geysermc.mcprotocollib.protocol.data.game.level.block.BlockEntityType;
|
||||
import org.geysermc.mcprotocollib.protocol.data.game.level.event.LevelEvent;
|
||||
import org.geysermc.mcprotocollib.protocol.data.game.level.particle.ParticleType;
|
||||
import org.geysermc.mcprotocollib.protocol.data.game.recipe.RecipeType;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.EnumMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.IdentityHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
@ -159,13 +158,18 @@ public final class Registries {
|
||||
/**
|
||||
* A versioned registry holding all the recipes, with the net ID being the key, and {@link GeyserRecipe} as the value.
|
||||
*/
|
||||
public static final SimpleMappedDeferredRegistry<RecipeType, List<GeyserRecipe>> RECIPES = SimpleMappedDeferredRegistry.create("mappings/recipes.nbt", RecipeRegistryLoader::new);
|
||||
//public static final SimpleMappedDeferredRegistry<RecipeType, List<GeyserRecipe>> RECIPES = SimpleMappedDeferredRegistry.create("mappings/recipes.nbt", RecipeRegistryLoader::new);
|
||||
|
||||
/**
|
||||
* A mapped registry holding {@link ResourcePack}'s with the pack uuid as keys.
|
||||
*/
|
||||
public static final SimpleMappedDeferredRegistry<String, ResourcePack> RESOURCE_PACKS = SimpleMappedDeferredRegistry.create(GeyserImpl.getInstance().packDirectory(), RegistryLoaders.RESOURCE_PACKS);
|
||||
|
||||
/**
|
||||
* A versioned registry holding most Bedrock tags, with the Java item list (sorted) being the key, and the tag name as the value.
|
||||
*/
|
||||
public static final VersionedRegistry<Object2ObjectMap<int[], String>> TAGS = VersionedRegistry.create(RegistryLoaders.empty(Int2ObjectOpenHashMap::new));
|
||||
|
||||
/**
|
||||
* A mapped registry holding sound identifiers to their corresponding {@link SoundMapping}.
|
||||
*/
|
||||
@ -195,7 +199,7 @@ public final class Registries {
|
||||
BLOCK_ENTITIES.load();
|
||||
PARTICLES.load();
|
||||
// load potion mixes later
|
||||
RECIPES.load();
|
||||
//RECIPES.load();
|
||||
RESOURCE_PACKS.load();
|
||||
SOUNDS.load();
|
||||
SOUND_LEVEL_EVENTS.load();
|
||||
@ -205,6 +209,7 @@ public final class Registries {
|
||||
public static void populate() {
|
||||
PacketRegistryPopulator.populate();
|
||||
ItemRegistryPopulator.populate();
|
||||
TagRegistryPopulator.populate();
|
||||
|
||||
// potion mixes depend on other registries
|
||||
POTION_MIXES.load();
|
||||
|
@ -27,26 +27,15 @@ package org.geysermc.geyser.registry.loader;
|
||||
|
||||
import io.netty.buffer.ByteBuf;
|
||||
import io.netty.buffer.Unpooled;
|
||||
import it.unimi.dsi.fastutil.Pair;
|
||||
import it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap;
|
||||
import it.unimi.dsi.fastutil.objects.ObjectArrayList;
|
||||
import org.cloudburstmc.nbt.NBTInputStream;
|
||||
import org.cloudburstmc.nbt.NbtMap;
|
||||
import org.cloudburstmc.nbt.NbtType;
|
||||
import org.geysermc.geyser.GeyserImpl;
|
||||
import org.geysermc.geyser.inventory.recipe.GeyserRecipe;
|
||||
import org.geysermc.geyser.inventory.recipe.GeyserShapedRecipe;
|
||||
import org.geysermc.geyser.inventory.recipe.GeyserShapelessRecipe;
|
||||
import org.geysermc.geyser.text.GeyserLocale;
|
||||
import org.geysermc.mcprotocollib.protocol.codec.MinecraftCodec;
|
||||
import org.geysermc.mcprotocollib.protocol.codec.MinecraftCodecHelper;
|
||||
import org.geysermc.mcprotocollib.protocol.data.game.item.ItemStack;
|
||||
import org.geysermc.mcprotocollib.protocol.data.game.item.component.DataComponents;
|
||||
import org.geysermc.mcprotocollib.protocol.data.game.recipe.Ingredient;
|
||||
import org.geysermc.mcprotocollib.protocol.data.game.recipe.RecipeType;
|
||||
|
||||
import java.io.DataInputStream;
|
||||
import java.io.InputStream;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Base64;
|
||||
import java.util.List;
|
||||
@ -56,38 +45,41 @@ import java.util.Map;
|
||||
* Populates the recipe registry with some recipes that Java does not send, to ensure they show up as intended
|
||||
* in the recipe book.
|
||||
*/
|
||||
public final class RecipeRegistryLoader implements RegistryLoader<String, Map<RecipeType, List<GeyserRecipe>>> {
|
||||
public abstract class RecipeRegistryLoader implements RegistryLoader<String, Map<Object, List<GeyserRecipe>>> {
|
||||
|
||||
@Override
|
||||
public Map<RecipeType, List<GeyserRecipe>> load(String input) {
|
||||
Map<RecipeType, List<GeyserRecipe>> deserializedRecipes = new Object2ObjectOpenHashMap<>();
|
||||
// @Override
|
||||
// public Map<RecipeType, List<GeyserRecipe>> load(String input) {
|
||||
// if (true) {
|
||||
// return Collections.emptyMap();
|
||||
// }
|
||||
// Map<RecipeType, List<GeyserRecipe>> deserializedRecipes = new Object2ObjectOpenHashMap<>();
|
||||
//
|
||||
// List<NbtMap> recipes;
|
||||
// try (InputStream stream = GeyserImpl.getInstance().getBootstrap().getResourceOrThrow("mappings/recipes.nbt")) {
|
||||
// try (NBTInputStream nbtStream = new NBTInputStream(new DataInputStream(stream))) {
|
||||
// recipes = ((NbtMap) nbtStream.readTag()).getList("recipes", NbtType.COMPOUND);
|
||||
// }
|
||||
// } catch (Exception e) {
|
||||
// throw new AssertionError(GeyserLocale.getLocaleStringLog("geyser.toolbox.fail.runtime_java"), e);
|
||||
// }
|
||||
//
|
||||
// MinecraftCodecHelper helper = MinecraftCodec.CODEC.getHelperFactory().get();
|
||||
// for (NbtMap recipeCollection : recipes) {
|
||||
// var pair = getRecipes(recipeCollection, helper);
|
||||
// deserializedRecipes.put(pair.key(), pair.value());
|
||||
// }
|
||||
// return deserializedRecipes;
|
||||
// }
|
||||
|
||||
List<NbtMap> recipes;
|
||||
try (InputStream stream = GeyserImpl.getInstance().getBootstrap().getResourceOrThrow("mappings/recipes.nbt")) {
|
||||
try (NBTInputStream nbtStream = new NBTInputStream(new DataInputStream(stream))) {
|
||||
recipes = ((NbtMap) nbtStream.readTag()).getList("recipes", NbtType.COMPOUND);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
throw new AssertionError(GeyserLocale.getLocaleStringLog("geyser.toolbox.fail.runtime_java"), e);
|
||||
}
|
||||
|
||||
MinecraftCodecHelper helper = MinecraftCodec.CODEC.getHelperFactory().get();
|
||||
for (NbtMap recipeCollection : recipes) {
|
||||
var pair = getRecipes(recipeCollection, helper);
|
||||
deserializedRecipes.put(pair.key(), pair.value());
|
||||
}
|
||||
return deserializedRecipes;
|
||||
}
|
||||
|
||||
private static Pair<RecipeType, List<GeyserRecipe>> getRecipes(NbtMap recipes, MinecraftCodecHelper helper) {
|
||||
List<NbtMap> typedRecipes = recipes.getList("recipes", NbtType.COMPOUND);
|
||||
RecipeType recipeType = RecipeType.from(recipes.getInt("recipe_type", -1));
|
||||
if (recipeType == RecipeType.CRAFTING_SPECIAL_TIPPEDARROW) {
|
||||
return Pair.of(recipeType, getShapedRecipes(typedRecipes, helper));
|
||||
} else {
|
||||
return Pair.of(recipeType, getShapelessRecipes(typedRecipes, helper));
|
||||
}
|
||||
}
|
||||
// private static Pair<RecipeType, List<GeyserRecipe>> getRecipes(NbtMap recipes, MinecraftCodecHelper helper) {
|
||||
// List<NbtMap> typedRecipes = recipes.getList("recipes", NbtType.COMPOUND);
|
||||
// RecipeType recipeType = RecipeType.from(recipes.getInt("recipe_type", -1));
|
||||
// if (recipeType == RecipeType.CRAFTING_SPECIAL_TIPPEDARROW) {
|
||||
// return Pair.of(recipeType, getShapedRecipes(typedRecipes, helper));
|
||||
// } else {
|
||||
// return Pair.of(recipeType, getShapelessRecipes(typedRecipes, helper));
|
||||
// }
|
||||
// }
|
||||
|
||||
private static List<GeyserRecipe> getShapelessRecipes(List<NbtMap> recipes, MinecraftCodecHelper helper) {
|
||||
List<GeyserRecipe> deserializedRecipes = new ObjectArrayList<>(recipes.size());
|
||||
@ -96,9 +88,9 @@ public final class RecipeRegistryLoader implements RegistryLoader<String, Map<Re
|
||||
List<NbtMap> rawInputs = recipe.getList("inputs", NbtType.COMPOUND);
|
||||
Ingredient[] javaInputs = new Ingredient[rawInputs.size()];
|
||||
for (int i = 0; i < rawInputs.size(); i++) {
|
||||
javaInputs[i] = new Ingredient(new ItemStack[] {toItemStack(rawInputs.get(i), helper)});
|
||||
//javaInputs[i] = new Ingredient(new ItemStack[] {toItemStack(rawInputs.get(i), helper)});
|
||||
}
|
||||
deserializedRecipes.add(new GeyserShapelessRecipe(javaInputs, output));
|
||||
//deserializedRecipes.add(new GeyserShapelessRecipe(javaInputs, output));
|
||||
}
|
||||
return deserializedRecipes;
|
||||
}
|
||||
@ -121,10 +113,10 @@ public final class RecipeRegistryLoader implements RegistryLoader<String, Map<Re
|
||||
for (int j = 0; i < shape.size() * shape.get(0).length; j++) {
|
||||
for (int index : shape.get(j)) {
|
||||
ItemStack stack = letterToRecipe.get(index);
|
||||
inputs[i++] = new Ingredient(new ItemStack[] {stack});
|
||||
//inputs[i++] = new Ingredient(new ItemStack[] {stack});
|
||||
}
|
||||
}
|
||||
deserializedRecipes.add(new GeyserShapedRecipe(shape.size(), shape.get(0).length, inputs, output));
|
||||
//deserializedRecipes.add(new GeyserShapedRecipe(shape.size(), shape.get(0).length, inputs, output));
|
||||
}
|
||||
return deserializedRecipes;
|
||||
}
|
||||
|
@ -196,11 +196,10 @@ public final class BlockRegistryPopulator {
|
||||
GeyserBedrockBlock[] bedrockRuntimeMap = new GeyserBedrockBlock[blockStates.size()];
|
||||
for (int i = 0; i < blockStates.size(); i++) {
|
||||
NbtMap tag = blockStates.get(i);
|
||||
if (blockStateOrderedMap.containsKey(tag)) {
|
||||
GeyserBedrockBlock block = new GeyserBedrockBlock(i, tag);
|
||||
if (blockStateOrderedMap.put(tag, block) != null) {
|
||||
throw new AssertionError("Duplicate block states in Bedrock palette: " + tag);
|
||||
}
|
||||
GeyserBedrockBlock block = new GeyserBedrockBlock(i, tag);
|
||||
blockStateOrderedMap.put(tag, block);
|
||||
bedrockRuntimeMap[i] = block;
|
||||
}
|
||||
|
||||
|
@ -84,6 +84,7 @@ import java.io.InputStream;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
@ -95,7 +96,7 @@ import java.util.concurrent.atomic.AtomicInteger;
|
||||
*/
|
||||
public class ItemRegistryPopulator {
|
||||
|
||||
record PaletteVersion(String version, int protocolVersion, Map<Item, String> javaOnlyItems, Remapper remapper) {
|
||||
record PaletteVersion(String version, int protocolVersion, Map<Item, Item> javaOnlyItems, Remapper remapper) {
|
||||
|
||||
public PaletteVersion(String version, int protocolVersion) {
|
||||
this(version, protocolVersion, Collections.emptyMap(), (item, mapping) -> mapping);
|
||||
@ -109,11 +110,17 @@ public class ItemRegistryPopulator {
|
||||
}
|
||||
|
||||
public static void populate() {
|
||||
List<Item> bundles = List.of(Items.BUNDLE, Items.BLACK_BUNDLE, Items.BLUE_BUNDLE, Items.BROWN_BUNDLE, Items.CYAN_BUNDLE, Items.GRAY_BUNDLE,
|
||||
Items.GREEN_BUNDLE, Items.LIGHT_BLUE_BUNDLE, Items.LIGHT_GRAY_BUNDLE, Items.LIME_BUNDLE, Items.MAGENTA_BUNDLE, Items.ORANGE_BUNDLE, Items.RED_BUNDLE,
|
||||
Items.PINK_BUNDLE, Items.PURPLE_BUNDLE, Items.WHITE_BUNDLE, Items.YELLOW_BUNDLE);
|
||||
Map<Item, Item> pre1_21_2Items = new HashMap<>();
|
||||
bundles.forEach(bundle -> pre1_21_2Items.put(bundle, Items.SHULKER_SHELL));
|
||||
|
||||
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(), Collections.emptyMap(), Conversion729_712::remapItem));
|
||||
paletteVersions.add(new PaletteVersion("1_21_30", Bedrock_v729.CODEC.getProtocolVersion(), Collections.emptyMap(), Conversion748_729::remapItem));
|
||||
paletteVersions.add(new PaletteVersion("1_20_80", Bedrock_v671.CODEC.getProtocolVersion(), pre1_21_2Items, Conversion685_671::remapItem));
|
||||
paletteVersions.add(new PaletteVersion("1_21_0", Bedrock_v685.CODEC.getProtocolVersion(), pre1_21_2Items, Conversion712_685::remapItem));
|
||||
paletteVersions.add(new PaletteVersion("1_21_20", Bedrock_v712.CODEC.getProtocolVersion(), pre1_21_2Items, Conversion729_712::remapItem));
|
||||
paletteVersions.add(new PaletteVersion("1_21_30", Bedrock_v729.CODEC.getProtocolVersion(), pre1_21_2Items, Conversion748_729::remapItem));
|
||||
paletteVersions.add(new PaletteVersion("1_21_40", Bedrock_v748.CODEC.getProtocolVersion()));
|
||||
|
||||
GeyserBootstrap bootstrap = GeyserImpl.getInstance().getBootstrap();
|
||||
@ -227,7 +234,7 @@ public class ItemRegistryPopulator {
|
||||
|
||||
Set<Item> javaOnlyItems = new ObjectOpenHashSet<>();
|
||||
Collections.addAll(javaOnlyItems, Items.SPECTRAL_ARROW, Items.DEBUG_STICK,
|
||||
Items.KNOWLEDGE_BOOK, Items.TIPPED_ARROW, Items.BUNDLE);
|
||||
Items.KNOWLEDGE_BOOK, Items.TIPPED_ARROW);
|
||||
if (!customItemsAllowed) {
|
||||
javaOnlyItems.add(Items.FURNACE_MINECART);
|
||||
}
|
||||
@ -243,9 +250,9 @@ public class ItemRegistryPopulator {
|
||||
throw new RuntimeException("Extra item in mappings? " + entry.getKey());
|
||||
}
|
||||
GeyserMappingItem mappingItem;
|
||||
String replacementItem = palette.javaOnlyItems().get(javaItem);
|
||||
Item replacementItem = palette.javaOnlyItems().get(javaItem);
|
||||
if (replacementItem != null) {
|
||||
mappingItem = items.get(replacementItem); // java only item, a java id fallback has been provided
|
||||
mappingItem = items.get(replacementItem.javaIdentifier()); // java only item, a java id fallback has been provided
|
||||
} else {
|
||||
// check if any mapping changes need to be made on this version
|
||||
mappingItem = palette.remapper().remap(javaItem, entry.getValue());
|
||||
|
@ -0,0 +1,135 @@
|
||||
/*
|
||||
* Copyright (c) 2024 GeyserMC. http://geysermc.org
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*
|
||||
* @author GeyserMC
|
||||
* @link https://github.com/GeyserMC/Geyser
|
||||
*/
|
||||
|
||||
package org.geysermc.geyser.registry.populator;
|
||||
|
||||
import com.google.gson.Gson;
|
||||
import com.google.gson.GsonBuilder;
|
||||
import com.google.gson.reflect.TypeToken;
|
||||
import it.unimi.dsi.fastutil.Hash;
|
||||
import it.unimi.dsi.fastutil.ints.IntArrayList;
|
||||
import it.unimi.dsi.fastutil.ints.IntList;
|
||||
import it.unimi.dsi.fastutil.objects.Object2ObjectOpenCustomHashMap;
|
||||
import it.unimi.dsi.fastutil.objects.ObjectIntPair;
|
||||
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.codec.v748.Bedrock_v748;
|
||||
import org.geysermc.geyser.GeyserBootstrap;
|
||||
import org.geysermc.geyser.GeyserImpl;
|
||||
import org.geysermc.geyser.item.type.Item;
|
||||
import org.geysermc.geyser.registry.Registries;
|
||||
import org.geysermc.geyser.registry.type.ItemMapping;
|
||||
import org.geysermc.geyser.registry.type.ItemMappings;
|
||||
|
||||
import java.io.InputStream;
|
||||
import java.io.InputStreamReader;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
public final class TagRegistryPopulator {
|
||||
private static final Gson GSON = new GsonBuilder().create(); // temporary
|
||||
|
||||
public static void populate() {
|
||||
Hash.Strategy<int[]> hashStrategy = new Hash.Strategy<>() {
|
||||
// Necessary so arrays can actually be compared
|
||||
@Override
|
||||
public int hashCode(int[] o) {
|
||||
return Arrays.hashCode(o);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(int[] a, int[] b) {
|
||||
return Arrays.equals(a, b);
|
||||
}
|
||||
};
|
||||
|
||||
List<ObjectIntPair<String>> paletteVersions = List.of(
|
||||
ObjectIntPair.of("1_20_80", Bedrock_v671.CODEC.getProtocolVersion()),
|
||||
ObjectIntPair.of("1_21_0", Bedrock_v685.CODEC.getProtocolVersion()),
|
||||
ObjectIntPair.of("1_21_20", Bedrock_v712.CODEC.getProtocolVersion()),
|
||||
ObjectIntPair.of("1_21_30", Bedrock_v729.CODEC.getProtocolVersion()),
|
||||
ObjectIntPair.of("1_21_40", Bedrock_v748.CODEC.getProtocolVersion())
|
||||
);
|
||||
TypeToken<Map<String, List<String>>> type = new TypeToken<>() {};
|
||||
|
||||
GeyserBootstrap bootstrap = GeyserImpl.getInstance().getBootstrap();
|
||||
|
||||
for (var palette : paletteVersions) {
|
||||
ItemMappings mappings = Registries.ITEMS.forVersion(palette.rightInt());
|
||||
|
||||
Map<String, List<String>> bedrockTags;
|
||||
try (InputStream stream = bootstrap.getResourceOrThrow(String.format("bedrock/item_tags.%s.json", palette.left()))) {
|
||||
bedrockTags = GSON.fromJson(new InputStreamReader(stream), type);
|
||||
} catch (Exception e) {
|
||||
throw new AssertionError("Unable to load Bedrock runtime item IDs", e);
|
||||
}
|
||||
|
||||
var javaItemsToBedrockTag = new Object2ObjectOpenCustomHashMap<int[], String>(hashStrategy);
|
||||
|
||||
for (var entry : bedrockTags.entrySet()) {
|
||||
List<String> value = entry.getValue();
|
||||
if (value.isEmpty() || value.size() == 1) {
|
||||
// For our usecase, we don't need this. Empty values are worthless; one value can just be a reference
|
||||
// to the item itself, instead of the tag.
|
||||
continue;
|
||||
}
|
||||
|
||||
// In some cases, the int list will need to be minimized
|
||||
IntList javaNetworkIds = new IntArrayList(value.size());
|
||||
for (int i = 0; i < value.size(); i++) {
|
||||
String bedrockIdentifier = value.get(i);
|
||||
Item javaItem = Registries.JAVA_ITEM_IDENTIFIERS.get(bedrockIdentifier);
|
||||
if (javaItem == null) {
|
||||
// Time to search the long way around.
|
||||
for (ItemMapping mapping : mappings.getItems()) {
|
||||
if (mapping.getBedrockIdentifier().equals(bedrockIdentifier)) {
|
||||
javaItem = mapping.getJavaItem();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (javaItem == null) {
|
||||
// Triggers for Bedrock-only spawn eggs. We don't care.
|
||||
continue;
|
||||
}
|
||||
|
||||
javaNetworkIds.add(javaItem.javaId());
|
||||
}
|
||||
|
||||
int[] javaNetworkIdArray = javaNetworkIds.toIntArray();
|
||||
// Sort IDs so equality checks just have to match if each is equal and not necessarily an order difference.
|
||||
Arrays.sort(javaNetworkIdArray);
|
||||
|
||||
javaItemsToBedrockTag.put(javaNetworkIdArray, entry.getKey());
|
||||
}
|
||||
|
||||
javaItemsToBedrockTag.trim();
|
||||
Registries.TAGS.register(palette.rightInt(), javaItemsToBedrockTag);
|
||||
}
|
||||
}
|
||||
}
|
@ -29,6 +29,7 @@ import com.google.gson.Gson;
|
||||
import com.google.gson.JsonObject;
|
||||
import io.netty.channel.Channel;
|
||||
import io.netty.channel.EventLoop;
|
||||
import it.unimi.dsi.fastutil.Pair;
|
||||
import it.unimi.dsi.fastutil.ints.Int2ObjectMap;
|
||||
import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap;
|
||||
import it.unimi.dsi.fastutil.objects.Object2IntMap;
|
||||
@ -77,13 +78,13 @@ import org.cloudburstmc.protocol.bedrock.data.command.SoftEnumUpdateType;
|
||||
import org.cloudburstmc.protocol.bedrock.data.definitions.DimensionDefinition;
|
||||
import org.cloudburstmc.protocol.bedrock.data.entity.EntityFlag;
|
||||
import org.cloudburstmc.protocol.bedrock.data.inventory.ItemData;
|
||||
import org.cloudburstmc.protocol.bedrock.data.inventory.crafting.recipe.CraftingRecipeData;
|
||||
import org.cloudburstmc.protocol.bedrock.packet.AvailableEntityIdentifiersPacket;
|
||||
import org.cloudburstmc.protocol.bedrock.packet.BedrockPacket;
|
||||
import org.cloudburstmc.protocol.bedrock.packet.BiomeDefinitionListPacket;
|
||||
import org.cloudburstmc.protocol.bedrock.packet.CameraPresetsPacket;
|
||||
import org.cloudburstmc.protocol.bedrock.packet.ChunkRadiusUpdatedPacket;
|
||||
import org.cloudburstmc.protocol.bedrock.packet.ClientboundCloseFormPacket;
|
||||
import org.cloudburstmc.protocol.bedrock.packet.CraftingDataPacket;
|
||||
import org.cloudburstmc.protocol.bedrock.packet.CreativeContentPacket;
|
||||
import org.cloudburstmc.protocol.bedrock.packet.DimensionDataPacket;
|
||||
import org.cloudburstmc.protocol.bedrock.packet.EmoteListPacket;
|
||||
@ -142,6 +143,7 @@ import org.geysermc.geyser.impl.camera.GeyserCameraData;
|
||||
import org.geysermc.geyser.inventory.Inventory;
|
||||
import org.geysermc.geyser.inventory.PlayerInventory;
|
||||
import org.geysermc.geyser.inventory.recipe.GeyserRecipe;
|
||||
import org.geysermc.geyser.inventory.recipe.GeyserSmithingRecipe;
|
||||
import org.geysermc.geyser.inventory.recipe.GeyserStonecutterData;
|
||||
import org.geysermc.geyser.item.Items;
|
||||
import org.geysermc.geyser.item.type.BlockItem;
|
||||
@ -161,6 +163,7 @@ import org.geysermc.geyser.session.cache.ChunkCache;
|
||||
import org.geysermc.geyser.session.cache.EntityCache;
|
||||
import org.geysermc.geyser.session.cache.EntityEffectCache;
|
||||
import org.geysermc.geyser.session.cache.FormCache;
|
||||
import org.geysermc.geyser.session.cache.InputCache;
|
||||
import org.geysermc.geyser.session.cache.LodestoneCache;
|
||||
import org.geysermc.geyser.session.cache.PistonCache;
|
||||
import org.geysermc.geyser.session.cache.PreferencesCache;
|
||||
@ -178,6 +181,7 @@ import org.geysermc.geyser.translator.inventory.InventoryTranslator;
|
||||
import org.geysermc.geyser.translator.text.MessageTranslator;
|
||||
import org.geysermc.geyser.util.ChunkUtils;
|
||||
import org.geysermc.geyser.util.EntityUtils;
|
||||
import org.geysermc.geyser.util.InventoryUtils;
|
||||
import org.geysermc.geyser.util.LoginEncryptionUtils;
|
||||
import org.geysermc.geyser.util.MinecraftAuthLogger;
|
||||
import org.geysermc.mcprotocollib.auth.GameProfile;
|
||||
@ -191,7 +195,6 @@ import org.geysermc.mcprotocollib.network.event.session.SessionAdapter;
|
||||
import org.geysermc.mcprotocollib.network.packet.Packet;
|
||||
import org.geysermc.mcprotocollib.network.tcp.TcpClientSession;
|
||||
import org.geysermc.mcprotocollib.network.tcp.TcpSession;
|
||||
import org.geysermc.mcprotocollib.protocol.ClientListener;
|
||||
import org.geysermc.mcprotocollib.protocol.MinecraftConstants;
|
||||
import org.geysermc.mcprotocollib.protocol.MinecraftProtocol;
|
||||
import org.geysermc.mcprotocollib.protocol.data.ProtocolState;
|
||||
@ -203,16 +206,15 @@ import org.geysermc.mcprotocollib.protocol.data.game.entity.player.Hand;
|
||||
import org.geysermc.mcprotocollib.protocol.data.game.entity.player.HandPreference;
|
||||
import org.geysermc.mcprotocollib.protocol.data.game.entity.player.PlayerAction;
|
||||
import org.geysermc.mcprotocollib.protocol.data.game.setting.ChatVisibility;
|
||||
import org.geysermc.mcprotocollib.protocol.data.game.setting.ParticleStatus;
|
||||
import org.geysermc.mcprotocollib.protocol.data.game.setting.SkinPart;
|
||||
import org.geysermc.mcprotocollib.protocol.data.game.statistic.CustomStatistic;
|
||||
import org.geysermc.mcprotocollib.protocol.data.game.statistic.Statistic;
|
||||
import org.geysermc.mcprotocollib.protocol.packet.common.serverbound.ServerboundClientInformationPacket;
|
||||
import org.geysermc.mcprotocollib.protocol.packet.configuration.clientbound.ClientboundFinishConfigurationPacket;
|
||||
import org.geysermc.mcprotocollib.protocol.packet.configuration.serverbound.ServerboundFinishConfigurationPacket;
|
||||
import org.geysermc.mcprotocollib.protocol.packet.handshake.serverbound.ClientIntentionPacket;
|
||||
import org.geysermc.mcprotocollib.protocol.packet.ingame.serverbound.ServerboundChatCommandSignedPacket;
|
||||
import org.geysermc.mcprotocollib.protocol.packet.ingame.serverbound.ServerboundChatPacket;
|
||||
import org.geysermc.mcprotocollib.protocol.packet.ingame.serverbound.player.ServerboundMovePlayerPosPacket;
|
||||
import org.geysermc.mcprotocollib.protocol.packet.ingame.serverbound.ServerboundClientTickEndPacket;
|
||||
import org.geysermc.mcprotocollib.protocol.packet.ingame.serverbound.player.ServerboundPlayerAbilitiesPacket;
|
||||
import org.geysermc.mcprotocollib.protocol.packet.ingame.serverbound.player.ServerboundPlayerActionPacket;
|
||||
import org.geysermc.mcprotocollib.protocol.packet.ingame.serverbound.player.ServerboundUseItemPacket;
|
||||
@ -254,7 +256,6 @@ public class GeyserSession implements GeyserConnection, GeyserCommandSource {
|
||||
private final EventLoop eventLoop;
|
||||
@Setter
|
||||
private AuthData authData;
|
||||
@Setter
|
||||
private BedrockClientData clientData;
|
||||
/**
|
||||
* Used for Floodgate skin uploading
|
||||
@ -278,6 +279,7 @@ public class GeyserSession implements GeyserConnection, GeyserCommandSource {
|
||||
private final EntityCache entityCache;
|
||||
private final EntityEffectCache effectCache;
|
||||
private final FormCache formCache;
|
||||
private final InputCache inputCache;
|
||||
private final LodestoneCache lodestoneCache;
|
||||
private final PistonCache pistonCache;
|
||||
private final PreferencesCache preferencesCache;
|
||||
@ -312,7 +314,7 @@ public class GeyserSession implements GeyserConnection, GeyserCommandSource {
|
||||
private final AtomicInteger itemNetId = new AtomicInteger(2);
|
||||
|
||||
@Setter
|
||||
private ScheduledFuture<?> craftingGridFuture;
|
||||
private ScheduledFuture<?> containerOutputFuture;
|
||||
|
||||
/**
|
||||
* Stores session collision
|
||||
@ -443,21 +445,22 @@ public class GeyserSession implements GeyserConnection, GeyserCommandSource {
|
||||
private Entity mouseoverEntity;
|
||||
|
||||
/**
|
||||
* Stores all Java recipes by recipe identifier, and matches them to all possible Bedrock recipe identifiers.
|
||||
* They are not 1:1, since Bedrock can have multiple recipes for the same Java recipe.
|
||||
* Stores all Java recipes by ID, and matches them to all possible Bedrock recipe identifiers.
|
||||
*/
|
||||
private final Map<String, List<String>> javaToBedrockRecipeIds;
|
||||
private final Int2ObjectMap<List<String>> javaToBedrockRecipeIds;
|
||||
|
||||
private final Int2ObjectMap<GeyserRecipe> craftingRecipes;
|
||||
@Setter
|
||||
private Int2ObjectMap<GeyserRecipe> craftingRecipes;
|
||||
private Pair<CraftingRecipeData, GeyserRecipe> lastCreatedRecipe = null; // TODO try to prevent sending duplicate recipes
|
||||
private final AtomicInteger lastRecipeNetId;
|
||||
|
||||
/**
|
||||
* Saves a list of all stonecutter recipes, for use in a stonecutter inventory.
|
||||
* The key is the Java ID of the item; the values are all the possible outputs' Java IDs sorted by their string identifier
|
||||
* The key is the Bedrock recipe net ID; the values are their respective output and button ID.
|
||||
*/
|
||||
@Setter
|
||||
private Int2ObjectMap<GeyserStonecutterData> stonecutterRecipes;
|
||||
private final List<GeyserSmithingRecipe> smithingRecipes = new ArrayList<>();
|
||||
|
||||
/**
|
||||
* Whether to work around 1.13's different behavior in villager trading menus.
|
||||
@ -526,18 +529,6 @@ public class GeyserSession implements GeyserConnection, GeyserCommandSource {
|
||||
@Setter
|
||||
private boolean placedBucket;
|
||||
|
||||
/**
|
||||
* Used to send a movement packet every three seconds if the player hasn't moved. Prevents timeouts when AFK in certain instances.
|
||||
*/
|
||||
@Setter
|
||||
private long lastMovementTimestamp = System.currentTimeMillis();
|
||||
|
||||
/**
|
||||
* Used to send a ServerboundMoveVehiclePacket for every PlayerInputPacket after idling on a boat/horse for more than 100ms
|
||||
*/
|
||||
@Setter
|
||||
private long lastVehicleMoveTimestamp = System.currentTimeMillis();
|
||||
|
||||
/**
|
||||
* Counts how many ticks have occurred since an arm animation started.
|
||||
* -1 means there is no active arm swing; -2 means an arm swing will start in a tick.
|
||||
@ -675,13 +666,14 @@ public class GeyserSession implements GeyserConnection, GeyserCommandSource {
|
||||
this.entityCache = new EntityCache(this);
|
||||
this.effectCache = new EntityEffectCache();
|
||||
this.formCache = new FormCache(this);
|
||||
this.inputCache = new InputCache(this);
|
||||
this.lodestoneCache = new LodestoneCache();
|
||||
this.pistonCache = new PistonCache(this);
|
||||
this.preferencesCache = new PreferencesCache(this);
|
||||
this.registryCache = new RegistryCache(this);
|
||||
this.skullCache = new SkullCache(this);
|
||||
this.structureBlockCache = new StructureBlockCache();
|
||||
this.tagCache = new TagCache();
|
||||
this.tagCache = new TagCache(this);
|
||||
this.worldCache = new WorldCache(this);
|
||||
this.cameraData = new GeyserCameraData(this);
|
||||
this.entityData = new GeyserEntityData(this);
|
||||
@ -696,8 +688,8 @@ public class GeyserSession implements GeyserConnection, GeyserCommandSource {
|
||||
this.playerInventory = new PlayerInventory();
|
||||
this.openInventory = null;
|
||||
this.craftingRecipes = new Int2ObjectOpenHashMap<>();
|
||||
this.javaToBedrockRecipeIds = new Object2ObjectOpenHashMap<>();
|
||||
this.lastRecipeNetId = new AtomicInteger(1);
|
||||
this.javaToBedrockRecipeIds = new Int2ObjectOpenHashMap<>();
|
||||
this.lastRecipeNetId = new AtomicInteger(InventoryUtils.LAST_RECIPE_NET_ID + 1);
|
||||
|
||||
this.spawned = false;
|
||||
this.loggedIn = false;
|
||||
@ -769,12 +761,6 @@ public class GeyserSession implements GeyserConnection, GeyserCommandSource {
|
||||
creativePacket.setContents(this.itemMappings.getCreativeItems());
|
||||
upstream.sendPacket(creativePacket);
|
||||
|
||||
// Potion mixes are registered by default, as they are needed to be able to put ingredients into the brewing stand.
|
||||
CraftingDataPacket craftingDataPacket = new CraftingDataPacket();
|
||||
craftingDataPacket.setCleanRecipes(true);
|
||||
craftingDataPacket.getPotionMixData().addAll(Registries.POTION_MIXES.forVersion(this.upstream.getProtocolVersion()));
|
||||
upstream.sendPacket(craftingDataPacket);
|
||||
|
||||
PlayStatusPacket playStatusPacket = new PlayStatusPacket();
|
||||
playStatusPacket.setStatus(PlayStatusPacket.Status.PLAYER_SPAWN);
|
||||
upstream.sendPacket(playStatusPacket);
|
||||
@ -1091,6 +1077,11 @@ public class GeyserSession implements GeyserConnection, GeyserCommandSource {
|
||||
|
||||
// Download and load the language for the player
|
||||
MinecraftLocale.downloadAndLoadLocale(locale);
|
||||
|
||||
// if (sentSpawnPacket && !GameProtocol.isPre1_21_2(GeyserSession.this)) {
|
||||
// // Possible form to close.
|
||||
// upstream.sendPacket(new ClientboundCloseFormPacket());
|
||||
// }
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -1269,18 +1260,6 @@ public class GeyserSession implements GeyserConnection, GeyserCommandSource {
|
||||
protected void tick() {
|
||||
try {
|
||||
pistonCache.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
|
||||
Vector3d position = collisionManager.adjustBedrockPosition(playerEntity.getPosition(), playerEntity.isOnGround(), false);
|
||||
// A null return value cancels the packet
|
||||
if (position != null) {
|
||||
ServerboundMovePlayerPosPacket packet = new ServerboundMovePlayerPosPacket(playerEntity.isOnGround(),
|
||||
position.getX(), position.getY(), position.getZ());
|
||||
sendDownstreamGamePacket(packet);
|
||||
}
|
||||
lastMovementTimestamp = System.currentTimeMillis();
|
||||
}
|
||||
|
||||
if (worldBorder.isResizing()) {
|
||||
worldBorder.resize();
|
||||
@ -1338,6 +1317,12 @@ public class GeyserSession implements GeyserConnection, GeyserCommandSource {
|
||||
armAnimationTicks = -1;
|
||||
}
|
||||
}
|
||||
|
||||
if (spawned) {
|
||||
// Could move this to the PlayerAuthInput translator, in the event the player lags
|
||||
// but this will work once we implement matching Java custom tick cycles
|
||||
sendDownstreamGamePacket(ServerboundClientTickEndPacket.INSTANCE);
|
||||
}
|
||||
} catch (Throwable throwable) {
|
||||
throwable.printStackTrace();
|
||||
}
|
||||
@ -1396,14 +1381,28 @@ public class GeyserSession implements GeyserConnection, GeyserCommandSource {
|
||||
}
|
||||
|
||||
public void setSwimming(boolean swimming) {
|
||||
if (swimming) {
|
||||
if (!swimming && playerEntity.getFlag(EntityFlag.CRAWLING)) {
|
||||
// Do not update bounding box.
|
||||
playerEntity.setFlag(EntityFlag.SWIMMING, false);
|
||||
playerEntity.updateBedrockMetadata();
|
||||
return;
|
||||
}
|
||||
toggleSwimmingPose(swimming, EntityFlag.SWIMMING);
|
||||
}
|
||||
|
||||
public void setCrawling(boolean crawling) {
|
||||
toggleSwimmingPose(crawling, EntityFlag.CRAWLING);
|
||||
}
|
||||
|
||||
private void toggleSwimmingPose(boolean crawling, EntityFlag flag) {
|
||||
if (crawling) {
|
||||
this.pose = Pose.SWIMMING;
|
||||
playerEntity.setBoundingBoxHeight(0.6f);
|
||||
} else {
|
||||
this.pose = Pose.STANDING;
|
||||
playerEntity.setBoundingBoxHeight(playerEntity.getDefinition().height());
|
||||
}
|
||||
playerEntity.setFlag(EntityFlag.SWIMMING, swimming);
|
||||
playerEntity.setFlag(flag, crawling);
|
||||
playerEntity.updateBedrockMetadata();
|
||||
}
|
||||
|
||||
@ -1423,6 +1422,12 @@ public class GeyserSession implements GeyserConnection, GeyserCommandSource {
|
||||
this.cameraData.handleGameModeChange(currentlySpectator, newGamemode);
|
||||
}
|
||||
|
||||
public void setClientData(BedrockClientData data) {
|
||||
this.clientData = data;
|
||||
this.inputCache.setInputMode(
|
||||
org.cloudburstmc.protocol.bedrock.data.InputMode.values()[data.getCurrentInputMode().ordinal()]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Convenience method to reduce amount of duplicate code. Sends ServerboundUseItemPacket.
|
||||
*/
|
||||
@ -1671,7 +1676,7 @@ public class GeyserSession implements GeyserConnection, GeyserCommandSource {
|
||||
|
||||
startGamePacket.setChatRestrictionLevel(ChatRestrictionLevel.NONE);
|
||||
|
||||
startGamePacket.setAuthoritativeMovementMode(AuthoritativeMovementMode.CLIENT);
|
||||
startGamePacket.setAuthoritativeMovementMode(AuthoritativeMovementMode.SERVER);
|
||||
startGamePacket.setRewindHistorySize(0);
|
||||
startGamePacket.setServerAuthoritativeBlockBreaking(false);
|
||||
|
||||
@ -1969,7 +1974,7 @@ public class GeyserSession implements GeyserConnection, GeyserCommandSource {
|
||||
public void sendJavaClientSettings() {
|
||||
ServerboundClientInformationPacket clientSettingsPacket = new ServerboundClientInformationPacket(locale(),
|
||||
getRenderDistance(), ChatVisibility.FULL, true, SKIN_PARTS,
|
||||
HandPreference.RIGHT_HAND, false, true);
|
||||
HandPreference.RIGHT_HAND, false, true, ParticleStatus.ALL); // TODO particle status
|
||||
sendDownstreamPacket(clientSettingsPacket);
|
||||
}
|
||||
|
||||
@ -2136,7 +2141,7 @@ public class GeyserSession implements GeyserConnection, GeyserCommandSource {
|
||||
|
||||
@Override
|
||||
public @NonNull InputMode inputMode() {
|
||||
return InputMode.values()[clientData.getCurrentInputMode().ordinal()]; //todo
|
||||
return InputMode.values()[inputCache.getInputMode().ordinal()]; //todo
|
||||
}
|
||||
|
||||
@Override
|
||||
|
112
core/src/main/java/org/geysermc/geyser/session/cache/InputCache.java
vendored
Normale Datei
112
core/src/main/java/org/geysermc/geyser/session/cache/InputCache.java
vendored
Normale Datei
@ -0,0 +1,112 @@
|
||||
/*
|
||||
* Copyright (c) 2024 GeyserMC. http://geysermc.org
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*
|
||||
* @author GeyserMC
|
||||
* @link https://github.com/GeyserMC/Geyser
|
||||
*/
|
||||
|
||||
package org.geysermc.geyser.session.cache;
|
||||
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
|
||||
import org.cloudburstmc.math.vector.Vector2f;
|
||||
import org.cloudburstmc.protocol.bedrock.data.InputMode;
|
||||
import org.cloudburstmc.protocol.bedrock.data.PlayerAuthInputData;
|
||||
import org.cloudburstmc.protocol.bedrock.packet.PlayerAuthInputPacket;
|
||||
import org.geysermc.geyser.session.GeyserSession;
|
||||
import org.geysermc.mcprotocollib.protocol.packet.ingame.serverbound.level.ServerboundPlayerInputPacket;
|
||||
|
||||
import java.util.Set;
|
||||
|
||||
public final class InputCache {
|
||||
private final GeyserSession session;
|
||||
private ServerboundPlayerInputPacket inputPacket = new ServerboundPlayerInputPacket(false, false, false, false, false, false, false);
|
||||
private boolean lastHorizontalCollision;
|
||||
private int ticksSinceLastMovePacket;
|
||||
@Getter @Setter
|
||||
private int jumpingTicks;
|
||||
@Getter @Setter
|
||||
private float jumpScale;
|
||||
@Getter @Setter
|
||||
private @MonotonicNonNull InputMode inputMode;
|
||||
|
||||
public InputCache(GeyserSession session) {
|
||||
this.session = session;
|
||||
}
|
||||
|
||||
public void processInputs(PlayerAuthInputPacket packet) {
|
||||
// Input is sent to the server before packet positions, as of 1.21.2
|
||||
Set<PlayerAuthInputData> bedrockInput = packet.getInputData();
|
||||
var oldInputPacket = this.inputPacket;
|
||||
this.inputMode = packet.getInputMode();
|
||||
|
||||
boolean up, down, left, right;
|
||||
if (this.inputMode == InputMode.MOUSE) {
|
||||
up = bedrockInput.contains(PlayerAuthInputData.UP);
|
||||
down = bedrockInput.contains(PlayerAuthInputData.DOWN);
|
||||
left = bedrockInput.contains(PlayerAuthInputData.LEFT);
|
||||
right = bedrockInput.contains(PlayerAuthInputData.RIGHT);
|
||||
} else {
|
||||
// The above flags don't fire TODO test console
|
||||
Vector2f analogMovement = packet.getAnalogMoveVector();
|
||||
up = analogMovement.getY() > 0;
|
||||
down = analogMovement.getY() < 0;
|
||||
left = analogMovement.getX() > 0;
|
||||
right = analogMovement.getX() < 0;
|
||||
}
|
||||
|
||||
// TODO when is UP_LEFT, etc. used?
|
||||
this.inputPacket = this.inputPacket
|
||||
.withForward(up)
|
||||
.withBackward(down)
|
||||
.withLeft(left)
|
||||
.withRight(right)
|
||||
.withJump(bedrockInput.contains(PlayerAuthInputData.JUMPING)) // Looks like this only triggers when the JUMP key input is being pressed. There's also JUMP_DOWN?
|
||||
.withShift(bedrockInput.contains(PlayerAuthInputData.SNEAKING))
|
||||
.withSprint(bedrockInput.contains(PlayerAuthInputData.SPRINTING)); // SPRINTING will trigger even if the player isn't moving
|
||||
|
||||
if (oldInputPacket != this.inputPacket) { // Simple equality check is fine since we're checking for an instance change.
|
||||
session.sendDownstreamGamePacket(this.inputPacket);
|
||||
}
|
||||
}
|
||||
|
||||
public boolean wasJumping() {
|
||||
return this.inputPacket.isJump();
|
||||
}
|
||||
|
||||
public void markPositionPacketSent() {
|
||||
this.ticksSinceLastMovePacket = 0;
|
||||
}
|
||||
|
||||
public boolean shouldSendPositionReminder() {
|
||||
// NOTE: if we implement spectating entities, DO NOT TICK THIS LOGIC THEN.
|
||||
return ++this.ticksSinceLastMovePacket >= 20;
|
||||
}
|
||||
|
||||
public boolean lastHorizontalCollision() {
|
||||
return lastHorizontalCollision;
|
||||
}
|
||||
|
||||
public void setLastHorizontalCollision(boolean lastHorizontalCollision) {
|
||||
this.lastHorizontalCollision = lastHorizontalCollision;
|
||||
}
|
||||
}
|
@ -40,13 +40,16 @@ import org.cloudburstmc.protocol.bedrock.data.TrimPattern;
|
||||
import org.geysermc.geyser.GeyserImpl;
|
||||
import org.geysermc.geyser.entity.type.living.animal.tameable.WolfEntity;
|
||||
import org.geysermc.geyser.inventory.item.BannerPattern;
|
||||
import org.geysermc.geyser.inventory.item.GeyserInstrument;
|
||||
import org.geysermc.geyser.inventory.recipe.TrimRecipe;
|
||||
import org.geysermc.geyser.item.enchantment.Enchantment;
|
||||
import org.geysermc.geyser.level.JavaDimension;
|
||||
import org.geysermc.geyser.level.JukeboxSong;
|
||||
import org.geysermc.geyser.level.PaintingType;
|
||||
import org.geysermc.geyser.session.GeyserSession;
|
||||
import org.geysermc.geyser.session.cache.registry.JavaRegistries;
|
||||
import org.geysermc.geyser.session.cache.registry.JavaRegistry;
|
||||
import org.geysermc.geyser.session.cache.registry.JavaRegistryKey;
|
||||
import org.geysermc.geyser.session.cache.registry.RegistryEntryContext;
|
||||
import org.geysermc.geyser.session.cache.registry.SimpleJavaRegistry;
|
||||
import org.geysermc.geyser.text.ChatDecoration;
|
||||
@ -80,7 +83,8 @@ public final class RegistryCache {
|
||||
static {
|
||||
register("chat_type", cache -> cache.chatTypes, ChatDecoration::readChatType);
|
||||
register("dimension_type", cache -> cache.dimensions, JavaDimension::read);
|
||||
register("enchantment", cache -> cache.enchantments, Enchantment::read);
|
||||
register(JavaRegistries.ENCHANTMENT, cache -> cache.enchantments, Enchantment::read);
|
||||
register("instrument", cache -> cache.instruments, GeyserInstrument::read);
|
||||
register("jukebox_song", cache -> cache.jukeboxSongs, JukeboxSong::read);
|
||||
register("painting_variant", cache -> cache.paintings, context -> PaintingType.getByName(context.id()));
|
||||
register("trim_material", cache -> cache.trimMaterials, TrimRecipe::readTrimMaterial);
|
||||
@ -94,8 +98,7 @@ public final class RegistryCache {
|
||||
Map<Key, Map<Key, NbtMap>> defaults = new HashMap<>();
|
||||
// Don't create a keySet - no need to create the cached object in HashMap if we don't use it again
|
||||
REGISTRIES.forEach((key, $) -> {
|
||||
List<NbtMap> rawValues = tag.getCompound(key.asString())
|
||||
.getList("value", NbtType.COMPOUND);
|
||||
List<NbtMap> rawValues = tag.getCompound(key.asString()).getList("value", NbtType.COMPOUND);
|
||||
Map<Key, NbtMap> values = new HashMap<>();
|
||||
for (NbtMap value : rawValues) {
|
||||
Key name = MinecraftKey.key(value.getString("name"));
|
||||
@ -128,6 +131,7 @@ public final class RegistryCache {
|
||||
|
||||
private final JavaRegistry<BannerPattern> bannerPatterns = new SimpleJavaRegistry<>();
|
||||
private final JavaRegistry<WolfEntity.BuiltInWolfVariant> wolfVariants = new SimpleJavaRegistry<>();
|
||||
private final JavaRegistry<GeyserInstrument> instruments = new SimpleJavaRegistry<>();
|
||||
|
||||
public RegistryCache(GeyserSession session) {
|
||||
this.session = session;
|
||||
@ -152,8 +156,27 @@ public final class RegistryCache {
|
||||
* @param <T> the class that represents these entries.
|
||||
*/
|
||||
private static <T> void register(String registry, Function<RegistryCache, JavaRegistry<T>> localCacheFunction, Function<RegistryEntryContext, T> reader) {
|
||||
Key registryKey = MinecraftKey.key(registry);
|
||||
REGISTRIES.put(registryKey, (registryCache, entries) -> {
|
||||
register(MinecraftKey.key(registry), localCacheFunction, reader);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param registry the Java registry resource location.
|
||||
* @param localCacheFunction which local field in RegistryCache are we caching entries for this registry?
|
||||
* @param reader converts the RegistryEntry NBT into a class file
|
||||
* @param <T> the class that represents these entries.
|
||||
*/
|
||||
private static <T> void register(JavaRegistryKey<?> registry, Function<RegistryCache, JavaRegistry<T>> localCacheFunction, Function<RegistryEntryContext, T> reader) {
|
||||
register(registry.registryKey(), localCacheFunction, reader);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param registry the Java registry resource location.
|
||||
* @param localCacheFunction which local field in RegistryCache are we caching entries for this registry?
|
||||
* @param reader converts the RegistryEntry NBT into a class file
|
||||
* @param <T> the class that represents these entries.
|
||||
*/
|
||||
private static <T> void register(Key registry, Function<RegistryCache, JavaRegistry<T>> localCacheFunction, Function<RegistryEntryContext, T> reader) {
|
||||
REGISTRIES.put(registry, (registryCache, entries) -> {
|
||||
Map<Key, NbtMap> localRegistry = null;
|
||||
JavaRegistry<T> localCache = localCacheFunction.apply(registryCache);
|
||||
// Clear each local cache every time a new registry entry is given to us
|
||||
@ -172,7 +195,7 @@ public final class RegistryCache {
|
||||
// If the data is null, that's the server telling us we need to use our default values.
|
||||
if (entry.getData() == null) {
|
||||
if (localRegistry == null) { // Lazy initialize
|
||||
localRegistry = DEFAULTS.get(registryKey);
|
||||
localRegistry = DEFAULTS.get(registry);
|
||||
}
|
||||
entry = new RegistryEntry(entry.getId(), localRegistry.get(entry.getId()));
|
||||
}
|
||||
|
@ -26,116 +26,119 @@
|
||||
package org.geysermc.geyser.session.cache;
|
||||
|
||||
import it.unimi.dsi.fastutil.ints.IntArrays;
|
||||
import it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap;
|
||||
import net.kyori.adventure.key.Key;
|
||||
import org.checkerframework.checker.nullness.qual.Nullable;
|
||||
import org.geysermc.geyser.GeyserImpl;
|
||||
import org.geysermc.geyser.GeyserLogger;
|
||||
import org.geysermc.geyser.inventory.GeyserItemStack;
|
||||
import org.geysermc.geyser.item.type.Item;
|
||||
import org.geysermc.geyser.level.block.type.Block;
|
||||
import org.geysermc.geyser.session.GeyserSession;
|
||||
import org.geysermc.geyser.session.cache.tags.BlockTag;
|
||||
import org.geysermc.geyser.session.cache.tags.EnchantmentTag;
|
||||
import org.geysermc.geyser.session.cache.tags.ItemTag;
|
||||
import org.geysermc.geyser.session.cache.registry.JavaRegistries;
|
||||
import org.geysermc.geyser.session.cache.registry.JavaRegistryKey;
|
||||
import org.geysermc.geyser.session.cache.tags.GeyserHolderSet;
|
||||
import org.geysermc.geyser.session.cache.tags.Tag;
|
||||
import org.geysermc.geyser.util.MinecraftKey;
|
||||
import org.geysermc.geyser.util.Ordered;
|
||||
import org.geysermc.mcprotocollib.protocol.packet.common.clientbound.ClientboundUpdateTagsPacket;
|
||||
|
||||
import javax.annotation.ParametersAreNonnullByDefault;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import static org.geysermc.geyser.session.cache.tags.BlockTag.ALL_BLOCK_TAGS;
|
||||
import static org.geysermc.geyser.session.cache.tags.EnchantmentTag.ALL_ENCHANTMENT_TAGS;
|
||||
import static org.geysermc.geyser.session.cache.tags.ItemTag.ALL_ITEM_TAGS;
|
||||
|
||||
/**
|
||||
* Manages information sent from the {@link ClientboundUpdateTagsPacket}. If that packet is not sent, all lists here
|
||||
* will remain empty, matching Java Edition behavior.
|
||||
* will remain empty, matching Java Edition behavior. Looking up a tag that wasn't listed in that packet will return an empty array.
|
||||
* Only tags from suitable registries in {@link JavaRegistries} are stored. Read {@link JavaRegistryKey} for more information.
|
||||
*/
|
||||
@ParametersAreNonnullByDefault
|
||||
public final class TagCache {
|
||||
private final int[][] blocks = new int[ALL_BLOCK_TAGS.size()][];
|
||||
private final int[][] items = new int[ALL_ITEM_TAGS.size()][];
|
||||
private final int[][] enchantments = new int[ALL_ENCHANTMENT_TAGS.size()][];
|
||||
private final GeyserSession session;
|
||||
private final Map<Tag<?>, int[]> tags = new Object2ObjectOpenHashMap<>();
|
||||
|
||||
public TagCache(GeyserSession session) {
|
||||
this.session = session;
|
||||
}
|
||||
|
||||
public void loadPacket(GeyserSession session, ClientboundUpdateTagsPacket packet) {
|
||||
Map<Key, int[]> blockTags = packet.getTags().get(MinecraftKey.key("block"));
|
||||
loadTags("Block", blockTags, ALL_BLOCK_TAGS, this.blocks);
|
||||
|
||||
// Hack btw
|
||||
Map<Key, Map<Key, int[]>> allTags = packet.getTags();
|
||||
GeyserLogger logger = session.getGeyser().getLogger();
|
||||
int[] convertableToMud = blockTags.get(MinecraftKey.key("convertable_to_mud"));
|
||||
boolean emulatePost1_18Logic = convertableToMud != null && convertableToMud.length != 0;
|
||||
session.setEmulatePost1_18Logic(emulatePost1_18Logic);
|
||||
if (logger.isDebug()) {
|
||||
logger.debug("Emulating post 1.18 block predication logic for " + session.bedrockUsername() + "? " + emulatePost1_18Logic);
|
||||
}
|
||||
|
||||
Map<Key, int[]> itemTags = packet.getTags().get(MinecraftKey.key("item"));
|
||||
loadTags("Item", itemTags, ALL_ITEM_TAGS, this.items);
|
||||
this.tags.clear();
|
||||
|
||||
// Hack btw
|
||||
boolean emulatePost1_13Logic = itemTags.get(MinecraftKey.key("signs")).length > 1;
|
||||
session.setEmulatePost1_13Logic(emulatePost1_13Logic);
|
||||
if (logger.isDebug()) {
|
||||
logger.debug("Emulating post 1.13 villager logic for " + session.bedrockUsername() + "? " + emulatePost1_13Logic);
|
||||
}
|
||||
|
||||
Map<Key, int[]> enchantmentTags = packet.getTags().get(MinecraftKey.key("enchantment"));
|
||||
loadTags("Enchantment", enchantmentTags, ALL_ENCHANTMENT_TAGS, this.enchantments);
|
||||
}
|
||||
|
||||
private <T extends Ordered> void loadTags(String type, @Nullable Map<Key, int[]> packetTags, Map<Key, T> allTags, int[][] localValues) {
|
||||
if (packetTags == null) {
|
||||
Arrays.fill(localValues, IntArrays.EMPTY_ARRAY);
|
||||
GeyserImpl.getInstance().getLogger().debug("Not loading " + type + " tags; they do not exist here.");
|
||||
return;
|
||||
}
|
||||
allTags.forEach((location, tag) -> {
|
||||
int[] values = packetTags.get(location);
|
||||
if (values != null) {
|
||||
if (values.length != 0) {
|
||||
localValues[tag.ordinal()] = values;
|
||||
} else {
|
||||
localValues[tag.ordinal()] = IntArrays.EMPTY_ARRAY;
|
||||
}
|
||||
} else {
|
||||
localValues[tag.ordinal()] = IntArrays.EMPTY_ARRAY;
|
||||
GeyserImpl.getInstance().getLogger().debug(type + " tag not found from server: " + location);
|
||||
for (Key registryKey : allTags.keySet()) {
|
||||
JavaRegistryKey<?> registry = JavaRegistries.fromKey(registryKey);
|
||||
if (registry == null || !registry.shouldStoreTags()) {
|
||||
logger.debug("Not loading tags for registry " + registryKey + " (registry not listed in JavaRegistries, or was not suitable to load tags)");
|
||||
continue;
|
||||
}
|
||||
});
|
||||
|
||||
Map<Key, int[]> registryTags = allTags.get(registryKey);
|
||||
|
||||
if (registry == JavaRegistries.BLOCK) {
|
||||
// Hack btw
|
||||
int[] convertableToMud = registryTags.get(MinecraftKey.key("convertable_to_mud"));
|
||||
boolean emulatePost1_18Logic = convertableToMud != null && convertableToMud.length != 0;
|
||||
session.setEmulatePost1_18Logic(emulatePost1_18Logic);
|
||||
if (logger.isDebug()) {
|
||||
logger.debug("Emulating post 1.18 block predication logic for " + session.bedrockUsername() + "? " + emulatePost1_18Logic);
|
||||
}
|
||||
} else if (registry == JavaRegistries.ITEM) {
|
||||
// Hack btw
|
||||
boolean emulatePost1_13Logic = registryTags.get(MinecraftKey.key("signs")).length > 1;
|
||||
session.setEmulatePost1_13Logic(emulatePost1_13Logic);
|
||||
if (logger.isDebug()) {
|
||||
logger.debug("Emulating post 1.13 villager logic for " + session.bedrockUsername() + "? " + emulatePost1_13Logic);
|
||||
}
|
||||
}
|
||||
|
||||
loadTags(registryTags, registry, registry == JavaRegistries.ITEM);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @return true if the block tag is present and contains this block mapping's Java ID.
|
||||
*/
|
||||
public boolean is(BlockTag tag, Block block) {
|
||||
int[] values = this.blocks[tag.ordinal()];
|
||||
return contains(values, block.javaId());
|
||||
private void loadTags(Map<Key, int[]> packetTags, JavaRegistryKey<?> registry, boolean sort) {
|
||||
for (Map.Entry<Key, int[]> tag : packetTags.entrySet()) {
|
||||
int[] value = tag.getValue();
|
||||
if (sort) {
|
||||
// Used in RecipeBookAddTranslator
|
||||
Arrays.sort(value);
|
||||
}
|
||||
this.tags.put(new Tag<>(registry, tag.getKey()), value);
|
||||
}
|
||||
}
|
||||
|
||||
public <T> boolean is(Tag<T> tag, T object) {
|
||||
return contains(getRaw(tag), tag.registry().toNetworkId(session, object));
|
||||
}
|
||||
|
||||
/**
|
||||
* @return true if the item tag is present and contains this item stack's Java ID.
|
||||
*/
|
||||
public boolean is(ItemTag tag, GeyserItemStack itemStack) {
|
||||
public boolean is(Tag<Item> tag, GeyserItemStack itemStack) {
|
||||
return is(tag, itemStack.asItem());
|
||||
}
|
||||
|
||||
/**
|
||||
* @return true if the item tag is present and contains this item's Java ID.
|
||||
* @return true if the specified network ID is in the given holder set.
|
||||
*/
|
||||
public boolean is(ItemTag tag, Item item) {
|
||||
int[] values = this.items[tag.ordinal()];
|
||||
return contains(values, item.javaId());
|
||||
public <T> boolean is(GeyserHolderSet<T> holderSet, T object) {
|
||||
return contains(holderSet.resolveRaw(this), holderSet.getRegistry().toNetworkId(session, object));
|
||||
}
|
||||
|
||||
public int[] get(ItemTag itemTag) {
|
||||
return this.items[itemTag.ordinal()];
|
||||
public <T> List<T> get(Tag<T> tag) {
|
||||
return mapRawArray(session, getRaw(tag), tag.registry());
|
||||
}
|
||||
|
||||
public int[] get(EnchantmentTag enchantmentTag) {
|
||||
return this.enchantments[enchantmentTag.ordinal()];
|
||||
/**
|
||||
* @return the network IDs in the given tag. This can be an empty list.
|
||||
*/
|
||||
public int[] getRaw(Tag<?> tag) {
|
||||
return this.tags.getOrDefault(tag, IntArrays.EMPTY_ARRAY);
|
||||
}
|
||||
|
||||
/**
|
||||
* Maps a raw array of network IDs to their respective objects.
|
||||
*/
|
||||
public static <T> List<T> mapRawArray(GeyserSession session, int[] array, JavaRegistryKey<T> registry) {
|
||||
return Arrays.stream(array).mapToObj(i -> registry.fromNetworkId(session, i)).toList();
|
||||
}
|
||||
|
||||
private static boolean contains(int[] array, int i) {
|
||||
|
@ -48,7 +48,7 @@ public class TeleportCache {
|
||||
/**
|
||||
* How many move packets the teleport can be unconfirmed for before it gets resent to the client
|
||||
*/
|
||||
private static final int RESEND_THRESHOLD = 5;
|
||||
private static final int RESEND_THRESHOLD = 20; // Make it one full second with auth input
|
||||
|
||||
private final double x, y, z;
|
||||
private final float pitch, yaw;
|
||||
|
@ -31,15 +31,18 @@ import it.unimi.dsi.fastutil.objects.Object2IntOpenHashMap;
|
||||
import it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
import net.kyori.adventure.key.Key;
|
||||
import org.checkerframework.checker.nullness.qual.NonNull;
|
||||
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.inventory.GeyserItemStack;
|
||||
import org.geysermc.geyser.scoreboard.Scoreboard;
|
||||
import org.geysermc.geyser.scoreboard.ScoreboardUpdater.ScoreboardSession;
|
||||
import org.geysermc.geyser.session.GeyserSession;
|
||||
import org.geysermc.geyser.util.ChunkUtils;
|
||||
import org.geysermc.mcprotocollib.protocol.data.game.item.component.DataComponentType;
|
||||
import org.geysermc.mcprotocollib.protocol.data.game.item.component.UseCooldown;
|
||||
import org.geysermc.mcprotocollib.protocol.data.game.setting.Difficulty;
|
||||
|
||||
import java.util.Iterator;
|
||||
@ -72,7 +75,7 @@ public final class WorldCache {
|
||||
@Setter
|
||||
private boolean editingSignOnFront;
|
||||
|
||||
private final Object2IntMap<Item> activeCooldowns = new Object2IntOpenHashMap<>(2);
|
||||
private final Object2IntMap<String> activeCooldowns = new Object2IntOpenHashMap<>(2);
|
||||
|
||||
public WorldCache(GeyserSession session) {
|
||||
this.session = session;
|
||||
@ -204,17 +207,24 @@ public final class WorldCache {
|
||||
return this.activeRecords.remove(pos);
|
||||
}
|
||||
|
||||
public void setCooldown(Item item, int ticks) {
|
||||
public void setCooldown(Key cooldownGroup, int ticks) {
|
||||
if (ticks == 0) {
|
||||
// As of Java 1.21
|
||||
this.activeCooldowns.removeInt(item);
|
||||
this.activeCooldowns.removeInt(cooldownGroup.asString());
|
||||
return;
|
||||
}
|
||||
this.activeCooldowns.put(item, session.getTicks() + ticks);
|
||||
this.activeCooldowns.put(cooldownGroup.asString(), session.getTicks() + ticks);
|
||||
}
|
||||
|
||||
public boolean hasCooldown(Item item) {
|
||||
return this.activeCooldowns.containsKey(item);
|
||||
public boolean hasCooldown(GeyserItemStack item) {
|
||||
UseCooldown cooldown = item.getComponent(DataComponentType.USE_COOLDOWN);
|
||||
String cooldownGroup;
|
||||
if (cooldown != null && cooldown.cooldownGroup() != null) {
|
||||
cooldownGroup = cooldown.cooldownGroup().asString();
|
||||
} else {
|
||||
cooldownGroup = item.asItem().javaIdentifier();
|
||||
}
|
||||
return this.activeCooldowns.containsKey(cooldownGroup);
|
||||
}
|
||||
|
||||
public void tick() {
|
||||
@ -222,9 +232,9 @@ public final class WorldCache {
|
||||
// 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);
|
||||
Iterator<Object2IntMap.Entry<String>> it = Object2IntMaps.fastIterator(this.activeCooldowns);
|
||||
while (it.hasNext()) {
|
||||
Object2IntMap.Entry<Item> entry = it.next();
|
||||
Object2IntMap.Entry<String> entry = it.next();
|
||||
if (entry.getIntValue() <= ticks) {
|
||||
it.remove();
|
||||
}
|
||||
|
87
core/src/main/java/org/geysermc/geyser/session/cache/registry/JavaRegistries.java
vendored
Normale Datei
87
core/src/main/java/org/geysermc/geyser/session/cache/registry/JavaRegistries.java
vendored
Normale Datei
@ -0,0 +1,87 @@
|
||||
/*
|
||||
* Copyright (c) 2024 GeyserMC. http://geysermc.org
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*
|
||||
* @author GeyserMC
|
||||
* @link https://github.com/GeyserMC/Geyser
|
||||
*/
|
||||
|
||||
package org.geysermc.geyser.session.cache.registry;
|
||||
|
||||
import net.kyori.adventure.key.Key;
|
||||
import org.checkerframework.checker.nullness.qual.Nullable;
|
||||
import org.geysermc.geyser.item.enchantment.Enchantment;
|
||||
import org.geysermc.geyser.item.type.Item;
|
||||
import org.geysermc.geyser.level.block.type.Block;
|
||||
import org.geysermc.geyser.registry.BlockRegistries;
|
||||
import org.geysermc.geyser.registry.ListRegistry;
|
||||
import org.geysermc.geyser.registry.Registries;
|
||||
import org.geysermc.geyser.session.cache.RegistryCache;
|
||||
import org.geysermc.geyser.util.MinecraftKey;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Stores {@link JavaRegistryKey} for Java registries that are used for loading of data-driven objects, tags, or both. Read {@link JavaRegistryKey} for more information on how to use one.
|
||||
*/
|
||||
public class JavaRegistries {
|
||||
private static final List<JavaRegistryKey<?>> VALUES = new ArrayList<>();
|
||||
|
||||
public static final JavaRegistryKey<Block> BLOCK = create("block", BlockRegistries.JAVA_BLOCKS, Block::javaId);
|
||||
public static final JavaRegistryKey<Item> ITEM = create("item", Registries.JAVA_ITEMS, Item::javaId);
|
||||
public static final JavaRegistryKey<Enchantment> ENCHANTMENT = create("enchantment", RegistryCache::enchantments);
|
||||
|
||||
private static <T> JavaRegistryKey<T> create(String key, JavaRegistryKey.NetworkSerializer<T> networkSerializer, JavaRegistryKey.NetworkDeserializer<T> networkDeserializer) {
|
||||
JavaRegistryKey<T> registry = new JavaRegistryKey<>(MinecraftKey.key(key), networkSerializer, networkDeserializer);
|
||||
VALUES.add(registry);
|
||||
return registry;
|
||||
}
|
||||
|
||||
private static <T> JavaRegistryKey<T> create(String key, ListRegistry<T> registry, RegistryNetworkMapper<T> networkSerializer) {
|
||||
return create(key, (session, object) -> networkSerializer.get(object), (session, id) -> registry.get(id));
|
||||
}
|
||||
|
||||
private static <T> JavaRegistryKey<T> create(String key, RegistryGetter<T> getter) {
|
||||
return create(key, (session, object) -> getter.get(session.getRegistryCache()).byValue(object), (session, id) -> getter.get(session.getRegistryCache()).byId(id));
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public static JavaRegistryKey<?> fromKey(Key registryKey) {
|
||||
for (JavaRegistryKey<?> registry : VALUES) {
|
||||
if (registry.registryKey().equals(registryKey)) {
|
||||
return registry;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@FunctionalInterface
|
||||
interface RegistryGetter<T> {
|
||||
|
||||
JavaRegistry<T> get(RegistryCache cache);
|
||||
}
|
||||
|
||||
@FunctionalInterface
|
||||
interface RegistryNetworkMapper<T> {
|
||||
|
||||
int get(T object);
|
||||
}
|
||||
}
|
86
core/src/main/java/org/geysermc/geyser/session/cache/registry/JavaRegistryKey.java
vendored
Normale Datei
86
core/src/main/java/org/geysermc/geyser/session/cache/registry/JavaRegistryKey.java
vendored
Normale Datei
@ -0,0 +1,86 @@
|
||||
/*
|
||||
* Copyright (c) 2024 GeyserMC. http://geysermc.org
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*
|
||||
* @author GeyserMC
|
||||
* @link https://github.com/GeyserMC/Geyser
|
||||
*/
|
||||
|
||||
package org.geysermc.geyser.session.cache.registry;
|
||||
|
||||
import net.kyori.adventure.key.Key;
|
||||
import org.geysermc.geyser.session.GeyserSession;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
/**
|
||||
* Defines a Java registry, which can be hardcoded or data-driven. This class doesn't store registry contents itself, that is handled by {@link org.geysermc.geyser.session.cache.RegistryCache} in the case of
|
||||
* data-driven registries and other classes in the case of hardcoded registries.
|
||||
*
|
||||
* <p>This class is used when, for a Java registry, data-driven objects or tags need to be loaded. Only one instance of this class should be created for each Java registry. Instances of this
|
||||
* class are kept in {@link JavaRegistries}, which also has useful methods for creating instances of this class. When only using a registry to load data-driven objects, the network (de)serializer parameters
|
||||
* can be null. For tag loading however, these are required, as {@link org.geysermc.geyser.session.cache.TagCache} relies on their functionality.</p>
|
||||
*
|
||||
* @param registryKey the registry key, as it appears on Java.
|
||||
* @param networkSerializer a method that converts an object in this registry to its network ID.
|
||||
* @param networkDeserializer a method that converts a network ID to an object in this registry.
|
||||
* @param <T> the object type this registry holds.
|
||||
*/
|
||||
public record JavaRegistryKey<T>(Key registryKey, @Nullable NetworkSerializer<T> networkSerializer, @Nullable NetworkDeserializer<T> networkDeserializer) {
|
||||
|
||||
/**
|
||||
* Converts an object in this registry to its network ID. This will fail if this registry doesn't have a network serializer.
|
||||
*/
|
||||
public int toNetworkId(GeyserSession session, T object) {
|
||||
if (networkSerializer == null) {
|
||||
throw new UnsupportedOperationException("Registry does not hava a network serializer");
|
||||
}
|
||||
return networkSerializer.toNetworkId(session, object);
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts a network ID to an object in this registry. This will fail if this registry doesn't have a network deserializer.
|
||||
*/
|
||||
public T fromNetworkId(GeyserSession session, int networkId) {
|
||||
if (networkDeserializer == null) {
|
||||
throw new UnsupportedOperationException("Registry does not hava a network deserializer");
|
||||
}
|
||||
return networkDeserializer.fromNetworkId(session, networkId);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return true if this registry has a network serializer and deserializer.
|
||||
*/
|
||||
public boolean shouldStoreTags() {
|
||||
return networkSerializer != null && networkDeserializer != null;
|
||||
}
|
||||
|
||||
@FunctionalInterface
|
||||
public interface NetworkSerializer<T> {
|
||||
|
||||
int toNetworkId(GeyserSession session, T object);
|
||||
}
|
||||
|
||||
@FunctionalInterface
|
||||
public interface NetworkDeserializer<T> {
|
||||
|
||||
T fromNetworkId(GeyserSession session, int networkId);
|
||||
}
|
||||
}
|
@ -25,214 +25,203 @@
|
||||
|
||||
package org.geysermc.geyser.session.cache.tags;
|
||||
|
||||
import net.kyori.adventure.key.Key;
|
||||
import org.geysermc.geyser.util.Ordered;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import org.geysermc.geyser.level.block.type.Block;
|
||||
import org.geysermc.geyser.session.cache.registry.JavaRegistries;
|
||||
import org.geysermc.geyser.util.MinecraftKey;
|
||||
|
||||
/**
|
||||
* Lists vanilla block tags.
|
||||
*/
|
||||
@SuppressWarnings("unused")
|
||||
public final class BlockTag implements Ordered {
|
||||
public static final Map<Key, BlockTag> ALL_BLOCK_TAGS = new HashMap<>();
|
||||
public final class BlockTag {
|
||||
public static final Tag<Block> WOOL = create("wool");
|
||||
public static final Tag<Block> PLANKS = create("planks");
|
||||
public static final Tag<Block> STONE_BRICKS = create("stone_bricks");
|
||||
public static final Tag<Block> WOODEN_BUTTONS = create("wooden_buttons");
|
||||
public static final Tag<Block> STONE_BUTTONS = create("stone_buttons");
|
||||
public static final Tag<Block> BUTTONS = create("buttons");
|
||||
public static final Tag<Block> WOOL_CARPETS = create("wool_carpets");
|
||||
public static final Tag<Block> WOODEN_DOORS = create("wooden_doors");
|
||||
public static final Tag<Block> MOB_INTERACTABLE_DOORS = create("mob_interactable_doors");
|
||||
public static final Tag<Block> WOODEN_STAIRS = create("wooden_stairs");
|
||||
public static final Tag<Block> WOODEN_SLABS = create("wooden_slabs");
|
||||
public static final Tag<Block> WOODEN_FENCES = create("wooden_fences");
|
||||
public static final Tag<Block> PRESSURE_PLATES = create("pressure_plates");
|
||||
public static final Tag<Block> WOODEN_PRESSURE_PLATES = create("wooden_pressure_plates");
|
||||
public static final Tag<Block> STONE_PRESSURE_PLATES = create("stone_pressure_plates");
|
||||
public static final Tag<Block> WOODEN_TRAPDOORS = create("wooden_trapdoors");
|
||||
public static final Tag<Block> DOORS = create("doors");
|
||||
public static final Tag<Block> SAPLINGS = create("saplings");
|
||||
public static final Tag<Block> LOGS_THAT_BURN = create("logs_that_burn");
|
||||
public static final Tag<Block> OVERWORLD_NATURAL_LOGS = create("overworld_natural_logs");
|
||||
public static final Tag<Block> LOGS = create("logs");
|
||||
public static final Tag<Block> DARK_OAK_LOGS = create("dark_oak_logs");
|
||||
public static final Tag<Block> OAK_LOGS = create("oak_logs");
|
||||
public static final Tag<Block> BIRCH_LOGS = create("birch_logs");
|
||||
public static final Tag<Block> ACACIA_LOGS = create("acacia_logs");
|
||||
public static final Tag<Block> CHERRY_LOGS = create("cherry_logs");
|
||||
public static final Tag<Block> JUNGLE_LOGS = create("jungle_logs");
|
||||
public static final Tag<Block> SPRUCE_LOGS = create("spruce_logs");
|
||||
public static final Tag<Block> MANGROVE_LOGS = create("mangrove_logs");
|
||||
public static final Tag<Block> CRIMSON_STEMS = create("crimson_stems");
|
||||
public static final Tag<Block> WARPED_STEMS = create("warped_stems");
|
||||
public static final Tag<Block> BAMBOO_BLOCKS = create("bamboo_blocks");
|
||||
public static final Tag<Block> WART_BLOCKS = create("wart_blocks");
|
||||
public static final Tag<Block> BANNERS = create("banners");
|
||||
public static final Tag<Block> SAND = create("sand");
|
||||
public static final Tag<Block> SMELTS_TO_GLASS = create("smelts_to_glass");
|
||||
public static final Tag<Block> STAIRS = create("stairs");
|
||||
public static final Tag<Block> SLABS = create("slabs");
|
||||
public static final Tag<Block> WALLS = create("walls");
|
||||
public static final Tag<Block> ANVIL = create("anvil");
|
||||
public static final Tag<Block> RAILS = create("rails");
|
||||
public static final Tag<Block> LEAVES = create("leaves");
|
||||
public static final Tag<Block> TRAPDOORS = create("trapdoors");
|
||||
public static final Tag<Block> SMALL_FLOWERS = create("small_flowers");
|
||||
public static final Tag<Block> BEDS = create("beds");
|
||||
public static final Tag<Block> FENCES = create("fences");
|
||||
public static final Tag<Block> TALL_FLOWERS = create("tall_flowers");
|
||||
public static final Tag<Block> FLOWERS = create("flowers");
|
||||
public static final Tag<Block> PIGLIN_REPELLENTS = create("piglin_repellents");
|
||||
public static final Tag<Block> GOLD_ORES = create("gold_ores");
|
||||
public static final Tag<Block> IRON_ORES = create("iron_ores");
|
||||
public static final Tag<Block> DIAMOND_ORES = create("diamond_ores");
|
||||
public static final Tag<Block> REDSTONE_ORES = create("redstone_ores");
|
||||
public static final Tag<Block> LAPIS_ORES = create("lapis_ores");
|
||||
public static final Tag<Block> COAL_ORES = create("coal_ores");
|
||||
public static final Tag<Block> EMERALD_ORES = create("emerald_ores");
|
||||
public static final Tag<Block> COPPER_ORES = create("copper_ores");
|
||||
public static final Tag<Block> CANDLES = create("candles");
|
||||
public static final Tag<Block> DIRT = create("dirt");
|
||||
public static final Tag<Block> TERRACOTTA = create("terracotta");
|
||||
public static final Tag<Block> BADLANDS_TERRACOTTA = create("badlands_terracotta");
|
||||
public static final Tag<Block> CONCRETE_POWDER = create("concrete_powder");
|
||||
public static final Tag<Block> COMPLETES_FIND_TREE_TUTORIAL = create("completes_find_tree_tutorial");
|
||||
public static final Tag<Block> FLOWER_POTS = create("flower_pots");
|
||||
public static final Tag<Block> ENDERMAN_HOLDABLE = create("enderman_holdable");
|
||||
public static final Tag<Block> ICE = create("ice");
|
||||
public static final Tag<Block> VALID_SPAWN = create("valid_spawn");
|
||||
public static final Tag<Block> IMPERMEABLE = create("impermeable");
|
||||
public static final Tag<Block> UNDERWATER_BONEMEALS = create("underwater_bonemeals");
|
||||
public static final Tag<Block> CORAL_BLOCKS = create("coral_blocks");
|
||||
public static final Tag<Block> WALL_CORALS = create("wall_corals");
|
||||
public static final Tag<Block> CORAL_PLANTS = create("coral_plants");
|
||||
public static final Tag<Block> CORALS = create("corals");
|
||||
public static final Tag<Block> BAMBOO_PLANTABLE_ON = create("bamboo_plantable_on");
|
||||
public static final Tag<Block> STANDING_SIGNS = create("standing_signs");
|
||||
public static final Tag<Block> WALL_SIGNS = create("wall_signs");
|
||||
public static final Tag<Block> SIGNS = create("signs");
|
||||
public static final Tag<Block> CEILING_HANGING_SIGNS = create("ceiling_hanging_signs");
|
||||
public static final Tag<Block> WALL_HANGING_SIGNS = create("wall_hanging_signs");
|
||||
public static final Tag<Block> ALL_HANGING_SIGNS = create("all_hanging_signs");
|
||||
public static final Tag<Block> ALL_SIGNS = create("all_signs");
|
||||
public static final Tag<Block> DRAGON_IMMUNE = create("dragon_immune");
|
||||
public static final Tag<Block> DRAGON_TRANSPARENT = create("dragon_transparent");
|
||||
public static final Tag<Block> WITHER_IMMUNE = create("wither_immune");
|
||||
public static final Tag<Block> WITHER_SUMMON_BASE_BLOCKS = create("wither_summon_base_blocks");
|
||||
public static final Tag<Block> BEEHIVES = create("beehives");
|
||||
public static final Tag<Block> CROPS = create("crops");
|
||||
public static final Tag<Block> BEE_GROWABLES = create("bee_growables");
|
||||
public static final Tag<Block> PORTALS = create("portals");
|
||||
public static final Tag<Block> FIRE = create("fire");
|
||||
public static final Tag<Block> NYLIUM = create("nylium");
|
||||
public static final Tag<Block> BEACON_BASE_BLOCKS = create("beacon_base_blocks");
|
||||
public static final Tag<Block> SOUL_SPEED_BLOCKS = create("soul_speed_blocks");
|
||||
public static final Tag<Block> WALL_POST_OVERRIDE = create("wall_post_override");
|
||||
public static final Tag<Block> CLIMBABLE = create("climbable");
|
||||
public static final Tag<Block> FALL_DAMAGE_RESETTING = create("fall_damage_resetting");
|
||||
public static final Tag<Block> SHULKER_BOXES = create("shulker_boxes");
|
||||
public static final Tag<Block> HOGLIN_REPELLENTS = create("hoglin_repellents");
|
||||
public static final Tag<Block> SOUL_FIRE_BASE_BLOCKS = create("soul_fire_base_blocks");
|
||||
public static final Tag<Block> STRIDER_WARM_BLOCKS = create("strider_warm_blocks");
|
||||
public static final Tag<Block> CAMPFIRES = create("campfires");
|
||||
public static final Tag<Block> GUARDED_BY_PIGLINS = create("guarded_by_piglins");
|
||||
public static final Tag<Block> PREVENT_MOB_SPAWNING_INSIDE = create("prevent_mob_spawning_inside");
|
||||
public static final Tag<Block> FENCE_GATES = create("fence_gates");
|
||||
public static final Tag<Block> UNSTABLE_BOTTOM_CENTER = create("unstable_bottom_center");
|
||||
public static final Tag<Block> MUSHROOM_GROW_BLOCK = create("mushroom_grow_block");
|
||||
public static final Tag<Block> INFINIBURN_OVERWORLD = create("infiniburn_overworld");
|
||||
public static final Tag<Block> INFINIBURN_NETHER = create("infiniburn_nether");
|
||||
public static final Tag<Block> INFINIBURN_END = create("infiniburn_end");
|
||||
public static final Tag<Block> BASE_STONE_OVERWORLD = create("base_stone_overworld");
|
||||
public static final Tag<Block> STONE_ORE_REPLACEABLES = create("stone_ore_replaceables");
|
||||
public static final Tag<Block> DEEPSLATE_ORE_REPLACEABLES = create("deepslate_ore_replaceables");
|
||||
public static final Tag<Block> BASE_STONE_NETHER = create("base_stone_nether");
|
||||
public static final Tag<Block> OVERWORLD_CARVER_REPLACEABLES = create("overworld_carver_replaceables");
|
||||
public static final Tag<Block> NETHER_CARVER_REPLACEABLES = create("nether_carver_replaceables");
|
||||
public static final Tag<Block> CANDLE_CAKES = create("candle_cakes");
|
||||
public static final Tag<Block> CAULDRONS = create("cauldrons");
|
||||
public static final Tag<Block> CRYSTAL_SOUND_BLOCKS = create("crystal_sound_blocks");
|
||||
public static final Tag<Block> INSIDE_STEP_SOUND_BLOCKS = create("inside_step_sound_blocks");
|
||||
public static final Tag<Block> COMBINATION_STEP_SOUND_BLOCKS = create("combination_step_sound_blocks");
|
||||
public static final Tag<Block> CAMEL_SAND_STEP_SOUND_BLOCKS = create("camel_sand_step_sound_blocks");
|
||||
public static final Tag<Block> OCCLUDES_VIBRATION_SIGNALS = create("occludes_vibration_signals");
|
||||
public static final Tag<Block> DAMPENS_VIBRATIONS = create("dampens_vibrations");
|
||||
public static final Tag<Block> DRIPSTONE_REPLACEABLE_BLOCKS = create("dripstone_replaceable_blocks");
|
||||
public static final Tag<Block> CAVE_VINES = create("cave_vines");
|
||||
public static final Tag<Block> MOSS_REPLACEABLE = create("moss_replaceable");
|
||||
public static final Tag<Block> LUSH_GROUND_REPLACEABLE = create("lush_ground_replaceable");
|
||||
public static final Tag<Block> AZALEA_ROOT_REPLACEABLE = create("azalea_root_replaceable");
|
||||
public static final Tag<Block> SMALL_DRIPLEAF_PLACEABLE = create("small_dripleaf_placeable");
|
||||
public static final Tag<Block> BIG_DRIPLEAF_PLACEABLE = create("big_dripleaf_placeable");
|
||||
public static final Tag<Block> SNOW = create("snow");
|
||||
public static final Tag<Block> MINEABLE_AXE = create("mineable/axe");
|
||||
public static final Tag<Block> MINEABLE_HOE = create("mineable/hoe");
|
||||
public static final Tag<Block> MINEABLE_PICKAXE = create("mineable/pickaxe");
|
||||
public static final Tag<Block> MINEABLE_SHOVEL = create("mineable/shovel");
|
||||
public static final Tag<Block> SWORD_EFFICIENT = create("sword_efficient");
|
||||
public static final Tag<Block> NEEDS_DIAMOND_TOOL = create("needs_diamond_tool");
|
||||
public static final Tag<Block> NEEDS_IRON_TOOL = create("needs_iron_tool");
|
||||
public static final Tag<Block> NEEDS_STONE_TOOL = create("needs_stone_tool");
|
||||
public static final Tag<Block> INCORRECT_FOR_NETHERITE_TOOL = create("incorrect_for_netherite_tool");
|
||||
public static final Tag<Block> INCORRECT_FOR_DIAMOND_TOOL = create("incorrect_for_diamond_tool");
|
||||
public static final Tag<Block> INCORRECT_FOR_IRON_TOOL = create("incorrect_for_iron_tool");
|
||||
public static final Tag<Block> INCORRECT_FOR_STONE_TOOL = create("incorrect_for_stone_tool");
|
||||
public static final Tag<Block> INCORRECT_FOR_GOLD_TOOL = create("incorrect_for_gold_tool");
|
||||
public static final Tag<Block> INCORRECT_FOR_WOODEN_TOOL = create("incorrect_for_wooden_tool");
|
||||
public static final Tag<Block> FEATURES_CANNOT_REPLACE = create("features_cannot_replace");
|
||||
public static final Tag<Block> LAVA_POOL_STONE_CANNOT_REPLACE = create("lava_pool_stone_cannot_replace");
|
||||
public static final Tag<Block> GEODE_INVALID_BLOCKS = create("geode_invalid_blocks");
|
||||
public static final Tag<Block> FROG_PREFER_JUMP_TO = create("frog_prefer_jump_to");
|
||||
public static final Tag<Block> SCULK_REPLACEABLE = create("sculk_replaceable");
|
||||
public static final Tag<Block> SCULK_REPLACEABLE_WORLD_GEN = create("sculk_replaceable_world_gen");
|
||||
public static final Tag<Block> ANCIENT_CITY_REPLACEABLE = create("ancient_city_replaceable");
|
||||
public static final Tag<Block> VIBRATION_RESONATORS = create("vibration_resonators");
|
||||
public static final Tag<Block> ANIMALS_SPAWNABLE_ON = create("animals_spawnable_on");
|
||||
public static final Tag<Block> ARMADILLO_SPAWNABLE_ON = create("armadillo_spawnable_on");
|
||||
public static final Tag<Block> AXOLOTLS_SPAWNABLE_ON = create("axolotls_spawnable_on");
|
||||
public static final Tag<Block> GOATS_SPAWNABLE_ON = create("goats_spawnable_on");
|
||||
public static final Tag<Block> MOOSHROOMS_SPAWNABLE_ON = create("mooshrooms_spawnable_on");
|
||||
public static final Tag<Block> PARROTS_SPAWNABLE_ON = create("parrots_spawnable_on");
|
||||
public static final Tag<Block> POLAR_BEARS_SPAWNABLE_ON_ALTERNATE = create("polar_bears_spawnable_on_alternate");
|
||||
public static final Tag<Block> RABBITS_SPAWNABLE_ON = create("rabbits_spawnable_on");
|
||||
public static final Tag<Block> FOXES_SPAWNABLE_ON = create("foxes_spawnable_on");
|
||||
public static final Tag<Block> WOLVES_SPAWNABLE_ON = create("wolves_spawnable_on");
|
||||
public static final Tag<Block> FROGS_SPAWNABLE_ON = create("frogs_spawnable_on");
|
||||
public static final Tag<Block> AZALEA_GROWS_ON = create("azalea_grows_on");
|
||||
public static final Tag<Block> CONVERTABLE_TO_MUD = create("convertable_to_mud");
|
||||
public static final Tag<Block> MANGROVE_LOGS_CAN_GROW_THROUGH = create("mangrove_logs_can_grow_through");
|
||||
public static final Tag<Block> MANGROVE_ROOTS_CAN_GROW_THROUGH = create("mangrove_roots_can_grow_through");
|
||||
public static final Tag<Block> DEAD_BUSH_MAY_PLACE_ON = create("dead_bush_may_place_on");
|
||||
public static final Tag<Block> SNAPS_GOAT_HORN = create("snaps_goat_horn");
|
||||
public static final Tag<Block> REPLACEABLE_BY_TREES = create("replaceable_by_trees");
|
||||
public static final Tag<Block> SNOW_LAYER_CANNOT_SURVIVE_ON = create("snow_layer_cannot_survive_on");
|
||||
public static final Tag<Block> SNOW_LAYER_CAN_SURVIVE_ON = create("snow_layer_can_survive_on");
|
||||
public static final Tag<Block> INVALID_SPAWN_INSIDE = create("invalid_spawn_inside");
|
||||
public static final Tag<Block> SNIFFER_DIGGABLE_BLOCK = create("sniffer_diggable_block");
|
||||
public static final Tag<Block> SNIFFER_EGG_HATCH_BOOST = create("sniffer_egg_hatch_boost");
|
||||
public static final Tag<Block> TRAIL_RUINS_REPLACEABLE = create("trail_ruins_replaceable");
|
||||
public static final Tag<Block> REPLACEABLE = create("replaceable");
|
||||
public static final Tag<Block> ENCHANTMENT_POWER_PROVIDER = create("enchantment_power_provider");
|
||||
public static final Tag<Block> ENCHANTMENT_POWER_TRANSMITTER = create("enchantment_power_transmitter");
|
||||
public static final Tag<Block> MAINTAINS_FARMLAND = create("maintains_farmland");
|
||||
public static final Tag<Block> BLOCKS_WIND_CHARGE_EXPLOSIONS = create("blocks_wind_charge_explosions");
|
||||
public static final Tag<Block> DOES_NOT_BLOCK_HOPPERS = create("does_not_block_hoppers");
|
||||
public static final Tag<Block> AIR = create("air");
|
||||
|
||||
public static final BlockTag WOOL = new BlockTag("wool");
|
||||
public static final BlockTag PLANKS = new BlockTag("planks");
|
||||
public static final BlockTag STONE_BRICKS = new BlockTag("stone_bricks");
|
||||
public static final BlockTag WOODEN_BUTTONS = new BlockTag("wooden_buttons");
|
||||
public static final BlockTag STONE_BUTTONS = new BlockTag("stone_buttons");
|
||||
public static final BlockTag BUTTONS = new BlockTag("buttons");
|
||||
public static final BlockTag WOOL_CARPETS = new BlockTag("wool_carpets");
|
||||
public static final BlockTag WOODEN_DOORS = new BlockTag("wooden_doors");
|
||||
public static final BlockTag MOB_INTERACTABLE_DOORS = new BlockTag("mob_interactable_doors");
|
||||
public static final BlockTag WOODEN_STAIRS = new BlockTag("wooden_stairs");
|
||||
public static final BlockTag WOODEN_SLABS = new BlockTag("wooden_slabs");
|
||||
public static final BlockTag WOODEN_FENCES = new BlockTag("wooden_fences");
|
||||
public static final BlockTag PRESSURE_PLATES = new BlockTag("pressure_plates");
|
||||
public static final BlockTag WOODEN_PRESSURE_PLATES = new BlockTag("wooden_pressure_plates");
|
||||
public static final BlockTag STONE_PRESSURE_PLATES = new BlockTag("stone_pressure_plates");
|
||||
public static final BlockTag WOODEN_TRAPDOORS = new BlockTag("wooden_trapdoors");
|
||||
public static final BlockTag DOORS = new BlockTag("doors");
|
||||
public static final BlockTag SAPLINGS = new BlockTag("saplings");
|
||||
public static final BlockTag LOGS_THAT_BURN = new BlockTag("logs_that_burn");
|
||||
public static final BlockTag OVERWORLD_NATURAL_LOGS = new BlockTag("overworld_natural_logs");
|
||||
public static final BlockTag LOGS = new BlockTag("logs");
|
||||
public static final BlockTag DARK_OAK_LOGS = new BlockTag("dark_oak_logs");
|
||||
public static final BlockTag OAK_LOGS = new BlockTag("oak_logs");
|
||||
public static final BlockTag BIRCH_LOGS = new BlockTag("birch_logs");
|
||||
public static final BlockTag ACACIA_LOGS = new BlockTag("acacia_logs");
|
||||
public static final BlockTag CHERRY_LOGS = new BlockTag("cherry_logs");
|
||||
public static final BlockTag JUNGLE_LOGS = new BlockTag("jungle_logs");
|
||||
public static final BlockTag SPRUCE_LOGS = new BlockTag("spruce_logs");
|
||||
public static final BlockTag MANGROVE_LOGS = new BlockTag("mangrove_logs");
|
||||
public static final BlockTag CRIMSON_STEMS = new BlockTag("crimson_stems");
|
||||
public static final BlockTag WARPED_STEMS = new BlockTag("warped_stems");
|
||||
public static final BlockTag BAMBOO_BLOCKS = new BlockTag("bamboo_blocks");
|
||||
public static final BlockTag WART_BLOCKS = new BlockTag("wart_blocks");
|
||||
public static final BlockTag BANNERS = new BlockTag("banners");
|
||||
public static final BlockTag SAND = new BlockTag("sand");
|
||||
public static final BlockTag SMELTS_TO_GLASS = new BlockTag("smelts_to_glass");
|
||||
public static final BlockTag STAIRS = new BlockTag("stairs");
|
||||
public static final BlockTag SLABS = new BlockTag("slabs");
|
||||
public static final BlockTag WALLS = new BlockTag("walls");
|
||||
public static final BlockTag ANVIL = new BlockTag("anvil");
|
||||
public static final BlockTag RAILS = new BlockTag("rails");
|
||||
public static final BlockTag LEAVES = new BlockTag("leaves");
|
||||
public static final BlockTag TRAPDOORS = new BlockTag("trapdoors");
|
||||
public static final BlockTag SMALL_FLOWERS = new BlockTag("small_flowers");
|
||||
public static final BlockTag BEDS = new BlockTag("beds");
|
||||
public static final BlockTag FENCES = new BlockTag("fences");
|
||||
public static final BlockTag TALL_FLOWERS = new BlockTag("tall_flowers");
|
||||
public static final BlockTag FLOWERS = new BlockTag("flowers");
|
||||
public static final BlockTag PIGLIN_REPELLENTS = new BlockTag("piglin_repellents");
|
||||
public static final BlockTag GOLD_ORES = new BlockTag("gold_ores");
|
||||
public static final BlockTag IRON_ORES = new BlockTag("iron_ores");
|
||||
public static final BlockTag DIAMOND_ORES = new BlockTag("diamond_ores");
|
||||
public static final BlockTag REDSTONE_ORES = new BlockTag("redstone_ores");
|
||||
public static final BlockTag LAPIS_ORES = new BlockTag("lapis_ores");
|
||||
public static final BlockTag COAL_ORES = new BlockTag("coal_ores");
|
||||
public static final BlockTag EMERALD_ORES = new BlockTag("emerald_ores");
|
||||
public static final BlockTag COPPER_ORES = new BlockTag("copper_ores");
|
||||
public static final BlockTag CANDLES = new BlockTag("candles");
|
||||
public static final BlockTag DIRT = new BlockTag("dirt");
|
||||
public static final BlockTag TERRACOTTA = new BlockTag("terracotta");
|
||||
public static final BlockTag BADLANDS_TERRACOTTA = new BlockTag("badlands_terracotta");
|
||||
public static final BlockTag CONCRETE_POWDER = new BlockTag("concrete_powder");
|
||||
public static final BlockTag COMPLETES_FIND_TREE_TUTORIAL = new BlockTag("completes_find_tree_tutorial");
|
||||
public static final BlockTag FLOWER_POTS = new BlockTag("flower_pots");
|
||||
public static final BlockTag ENDERMAN_HOLDABLE = new BlockTag("enderman_holdable");
|
||||
public static final BlockTag ICE = new BlockTag("ice");
|
||||
public static final BlockTag VALID_SPAWN = new BlockTag("valid_spawn");
|
||||
public static final BlockTag IMPERMEABLE = new BlockTag("impermeable");
|
||||
public static final BlockTag UNDERWATER_BONEMEALS = new BlockTag("underwater_bonemeals");
|
||||
public static final BlockTag CORAL_BLOCKS = new BlockTag("coral_blocks");
|
||||
public static final BlockTag WALL_CORALS = new BlockTag("wall_corals");
|
||||
public static final BlockTag CORAL_PLANTS = new BlockTag("coral_plants");
|
||||
public static final BlockTag CORALS = new BlockTag("corals");
|
||||
public static final BlockTag BAMBOO_PLANTABLE_ON = new BlockTag("bamboo_plantable_on");
|
||||
public static final BlockTag STANDING_SIGNS = new BlockTag("standing_signs");
|
||||
public static final BlockTag WALL_SIGNS = new BlockTag("wall_signs");
|
||||
public static final BlockTag SIGNS = new BlockTag("signs");
|
||||
public static final BlockTag CEILING_HANGING_SIGNS = new BlockTag("ceiling_hanging_signs");
|
||||
public static final BlockTag WALL_HANGING_SIGNS = new BlockTag("wall_hanging_signs");
|
||||
public static final BlockTag ALL_HANGING_SIGNS = new BlockTag("all_hanging_signs");
|
||||
public static final BlockTag ALL_SIGNS = new BlockTag("all_signs");
|
||||
public static final BlockTag DRAGON_IMMUNE = new BlockTag("dragon_immune");
|
||||
public static final BlockTag DRAGON_TRANSPARENT = new BlockTag("dragon_transparent");
|
||||
public static final BlockTag WITHER_IMMUNE = new BlockTag("wither_immune");
|
||||
public static final BlockTag WITHER_SUMMON_BASE_BLOCKS = new BlockTag("wither_summon_base_blocks");
|
||||
public static final BlockTag BEEHIVES = new BlockTag("beehives");
|
||||
public static final BlockTag CROPS = new BlockTag("crops");
|
||||
public static final BlockTag BEE_GROWABLES = new BlockTag("bee_growables");
|
||||
public static final BlockTag PORTALS = new BlockTag("portals");
|
||||
public static final BlockTag FIRE = new BlockTag("fire");
|
||||
public static final BlockTag NYLIUM = new BlockTag("nylium");
|
||||
public static final BlockTag BEACON_BASE_BLOCKS = new BlockTag("beacon_base_blocks");
|
||||
public static final BlockTag SOUL_SPEED_BLOCKS = new BlockTag("soul_speed_blocks");
|
||||
public static final BlockTag WALL_POST_OVERRIDE = new BlockTag("wall_post_override");
|
||||
public static final BlockTag CLIMBABLE = new BlockTag("climbable");
|
||||
public static final BlockTag FALL_DAMAGE_RESETTING = new BlockTag("fall_damage_resetting");
|
||||
public static final BlockTag SHULKER_BOXES = new BlockTag("shulker_boxes");
|
||||
public static final BlockTag HOGLIN_REPELLENTS = new BlockTag("hoglin_repellents");
|
||||
public static final BlockTag SOUL_FIRE_BASE_BLOCKS = new BlockTag("soul_fire_base_blocks");
|
||||
public static final BlockTag STRIDER_WARM_BLOCKS = new BlockTag("strider_warm_blocks");
|
||||
public static final BlockTag CAMPFIRES = new BlockTag("campfires");
|
||||
public static final BlockTag GUARDED_BY_PIGLINS = new BlockTag("guarded_by_piglins");
|
||||
public static final BlockTag PREVENT_MOB_SPAWNING_INSIDE = new BlockTag("prevent_mob_spawning_inside");
|
||||
public static final BlockTag FENCE_GATES = new BlockTag("fence_gates");
|
||||
public static final BlockTag UNSTABLE_BOTTOM_CENTER = new BlockTag("unstable_bottom_center");
|
||||
public static final BlockTag MUSHROOM_GROW_BLOCK = new BlockTag("mushroom_grow_block");
|
||||
public static final BlockTag INFINIBURN_OVERWORLD = new BlockTag("infiniburn_overworld");
|
||||
public static final BlockTag INFINIBURN_NETHER = new BlockTag("infiniburn_nether");
|
||||
public static final BlockTag INFINIBURN_END = new BlockTag("infiniburn_end");
|
||||
public static final BlockTag BASE_STONE_OVERWORLD = new BlockTag("base_stone_overworld");
|
||||
public static final BlockTag STONE_ORE_REPLACEABLES = new BlockTag("stone_ore_replaceables");
|
||||
public static final BlockTag DEEPSLATE_ORE_REPLACEABLES = new BlockTag("deepslate_ore_replaceables");
|
||||
public static final BlockTag BASE_STONE_NETHER = new BlockTag("base_stone_nether");
|
||||
public static final BlockTag OVERWORLD_CARVER_REPLACEABLES = new BlockTag("overworld_carver_replaceables");
|
||||
public static final BlockTag NETHER_CARVER_REPLACEABLES = new BlockTag("nether_carver_replaceables");
|
||||
public static final BlockTag CANDLE_CAKES = new BlockTag("candle_cakes");
|
||||
public static final BlockTag CAULDRONS = new BlockTag("cauldrons");
|
||||
public static final BlockTag CRYSTAL_SOUND_BLOCKS = new BlockTag("crystal_sound_blocks");
|
||||
public static final BlockTag INSIDE_STEP_SOUND_BLOCKS = new BlockTag("inside_step_sound_blocks");
|
||||
public static final BlockTag COMBINATION_STEP_SOUND_BLOCKS = new BlockTag("combination_step_sound_blocks");
|
||||
public static final BlockTag CAMEL_SAND_STEP_SOUND_BLOCKS = new BlockTag("camel_sand_step_sound_blocks");
|
||||
public static final BlockTag OCCLUDES_VIBRATION_SIGNALS = new BlockTag("occludes_vibration_signals");
|
||||
public static final BlockTag DAMPENS_VIBRATIONS = new BlockTag("dampens_vibrations");
|
||||
public static final BlockTag DRIPSTONE_REPLACEABLE_BLOCKS = new BlockTag("dripstone_replaceable_blocks");
|
||||
public static final BlockTag CAVE_VINES = new BlockTag("cave_vines");
|
||||
public static final BlockTag MOSS_REPLACEABLE = new BlockTag("moss_replaceable");
|
||||
public static final BlockTag LUSH_GROUND_REPLACEABLE = new BlockTag("lush_ground_replaceable");
|
||||
public static final BlockTag AZALEA_ROOT_REPLACEABLE = new BlockTag("azalea_root_replaceable");
|
||||
public static final BlockTag SMALL_DRIPLEAF_PLACEABLE = new BlockTag("small_dripleaf_placeable");
|
||||
public static final BlockTag BIG_DRIPLEAF_PLACEABLE = new BlockTag("big_dripleaf_placeable");
|
||||
public static final BlockTag SNOW = new BlockTag("snow");
|
||||
public static final BlockTag MINEABLE_AXE = new BlockTag("mineable/axe");
|
||||
public static final BlockTag MINEABLE_HOE = new BlockTag("mineable/hoe");
|
||||
public static final BlockTag MINEABLE_PICKAXE = new BlockTag("mineable/pickaxe");
|
||||
public static final BlockTag MINEABLE_SHOVEL = new BlockTag("mineable/shovel");
|
||||
public static final BlockTag SWORD_EFFICIENT = new BlockTag("sword_efficient");
|
||||
public static final BlockTag NEEDS_DIAMOND_TOOL = new BlockTag("needs_diamond_tool");
|
||||
public static final BlockTag NEEDS_IRON_TOOL = new BlockTag("needs_iron_tool");
|
||||
public static final BlockTag NEEDS_STONE_TOOL = new BlockTag("needs_stone_tool");
|
||||
public static final BlockTag INCORRECT_FOR_NETHERITE_TOOL = new BlockTag("incorrect_for_netherite_tool");
|
||||
public static final BlockTag INCORRECT_FOR_DIAMOND_TOOL = new BlockTag("incorrect_for_diamond_tool");
|
||||
public static final BlockTag INCORRECT_FOR_IRON_TOOL = new BlockTag("incorrect_for_iron_tool");
|
||||
public static final BlockTag INCORRECT_FOR_STONE_TOOL = new BlockTag("incorrect_for_stone_tool");
|
||||
public static final BlockTag INCORRECT_FOR_GOLD_TOOL = new BlockTag("incorrect_for_gold_tool");
|
||||
public static final BlockTag INCORRECT_FOR_WOODEN_TOOL = new BlockTag("incorrect_for_wooden_tool");
|
||||
public static final BlockTag FEATURES_CANNOT_REPLACE = new BlockTag("features_cannot_replace");
|
||||
public static final BlockTag LAVA_POOL_STONE_CANNOT_REPLACE = new BlockTag("lava_pool_stone_cannot_replace");
|
||||
public static final BlockTag GEODE_INVALID_BLOCKS = new BlockTag("geode_invalid_blocks");
|
||||
public static final BlockTag FROG_PREFER_JUMP_TO = new BlockTag("frog_prefer_jump_to");
|
||||
public static final BlockTag SCULK_REPLACEABLE = new BlockTag("sculk_replaceable");
|
||||
public static final BlockTag SCULK_REPLACEABLE_WORLD_GEN = new BlockTag("sculk_replaceable_world_gen");
|
||||
public static final BlockTag ANCIENT_CITY_REPLACEABLE = new BlockTag("ancient_city_replaceable");
|
||||
public static final BlockTag VIBRATION_RESONATORS = new BlockTag("vibration_resonators");
|
||||
public static final BlockTag ANIMALS_SPAWNABLE_ON = new BlockTag("animals_spawnable_on");
|
||||
public static final BlockTag ARMADILLO_SPAWNABLE_ON = new BlockTag("armadillo_spawnable_on");
|
||||
public static final BlockTag AXOLOTLS_SPAWNABLE_ON = new BlockTag("axolotls_spawnable_on");
|
||||
public static final BlockTag GOATS_SPAWNABLE_ON = new BlockTag("goats_spawnable_on");
|
||||
public static final BlockTag MOOSHROOMS_SPAWNABLE_ON = new BlockTag("mooshrooms_spawnable_on");
|
||||
public static final BlockTag PARROTS_SPAWNABLE_ON = new BlockTag("parrots_spawnable_on");
|
||||
public static final BlockTag POLAR_BEARS_SPAWNABLE_ON_ALTERNATE = new BlockTag("polar_bears_spawnable_on_alternate");
|
||||
public static final BlockTag RABBITS_SPAWNABLE_ON = new BlockTag("rabbits_spawnable_on");
|
||||
public static final BlockTag FOXES_SPAWNABLE_ON = new BlockTag("foxes_spawnable_on");
|
||||
public static final BlockTag WOLVES_SPAWNABLE_ON = new BlockTag("wolves_spawnable_on");
|
||||
public static final BlockTag FROGS_SPAWNABLE_ON = new BlockTag("frogs_spawnable_on");
|
||||
public static final BlockTag AZALEA_GROWS_ON = new BlockTag("azalea_grows_on");
|
||||
public static final BlockTag CONVERTABLE_TO_MUD = new BlockTag("convertable_to_mud");
|
||||
public static final BlockTag MANGROVE_LOGS_CAN_GROW_THROUGH = new BlockTag("mangrove_logs_can_grow_through");
|
||||
public static final BlockTag MANGROVE_ROOTS_CAN_GROW_THROUGH = new BlockTag("mangrove_roots_can_grow_through");
|
||||
public static final BlockTag DEAD_BUSH_MAY_PLACE_ON = new BlockTag("dead_bush_may_place_on");
|
||||
public static final BlockTag SNAPS_GOAT_HORN = new BlockTag("snaps_goat_horn");
|
||||
public static final BlockTag REPLACEABLE_BY_TREES = new BlockTag("replaceable_by_trees");
|
||||
public static final BlockTag SNOW_LAYER_CANNOT_SURVIVE_ON = new BlockTag("snow_layer_cannot_survive_on");
|
||||
public static final BlockTag SNOW_LAYER_CAN_SURVIVE_ON = new BlockTag("snow_layer_can_survive_on");
|
||||
public static final BlockTag INVALID_SPAWN_INSIDE = new BlockTag("invalid_spawn_inside");
|
||||
public static final BlockTag SNIFFER_DIGGABLE_BLOCK = new BlockTag("sniffer_diggable_block");
|
||||
public static final BlockTag SNIFFER_EGG_HATCH_BOOST = new BlockTag("sniffer_egg_hatch_boost");
|
||||
public static final BlockTag TRAIL_RUINS_REPLACEABLE = new BlockTag("trail_ruins_replaceable");
|
||||
public static final BlockTag REPLACEABLE = new BlockTag("replaceable");
|
||||
public static final BlockTag ENCHANTMENT_POWER_PROVIDER = new BlockTag("enchantment_power_provider");
|
||||
public static final BlockTag ENCHANTMENT_POWER_TRANSMITTER = new BlockTag("enchantment_power_transmitter");
|
||||
public static final BlockTag MAINTAINS_FARMLAND = new BlockTag("maintains_farmland");
|
||||
public static final BlockTag BLOCKS_WIND_CHARGE_EXPLOSIONS = new BlockTag("blocks_wind_charge_explosions");
|
||||
public static final BlockTag DOES_NOT_BLOCK_HOPPERS = new BlockTag("does_not_block_hoppers");
|
||||
public static final BlockTag AIR = new BlockTag("air");
|
||||
private BlockTag() {}
|
||||
|
||||
private final int id;
|
||||
|
||||
private BlockTag(String identifier) {
|
||||
this.id = ALL_BLOCK_TAGS.size();
|
||||
register(identifier, this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int ordinal() {
|
||||
return id;
|
||||
}
|
||||
|
||||
private static void register(String name, BlockTag tag) {
|
||||
ALL_BLOCK_TAGS.put(Key.key(name), tag);
|
||||
private static Tag<Block> create(String name) {
|
||||
return new Tag<>(JavaRegistries.BLOCK, MinecraftKey.key(name));
|
||||
}
|
||||
}
|
||||
|
@ -25,67 +25,55 @@
|
||||
|
||||
package org.geysermc.geyser.session.cache.tags;
|
||||
|
||||
import net.kyori.adventure.key.Key;
|
||||
import org.geysermc.geyser.item.enchantment.Enchantment;
|
||||
import org.geysermc.geyser.session.cache.registry.JavaRegistries;
|
||||
import org.geysermc.geyser.util.MinecraftKey;
|
||||
import org.geysermc.geyser.util.Ordered;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* Lists vanilla enchantment tags.
|
||||
*/
|
||||
@SuppressWarnings("unused")
|
||||
public final class EnchantmentTag implements Ordered {
|
||||
public static final Map<Key, EnchantmentTag> ALL_ENCHANTMENT_TAGS = new HashMap<>();
|
||||
public final class EnchantmentTag {
|
||||
public static final Tag<Enchantment> TOOLTIP_ORDER = create("tooltip_order");
|
||||
public static final Tag<Enchantment> EXCLUSIVE_SET_ARMOR = create("exclusive_set/armor");
|
||||
public static final Tag<Enchantment> EXCLUSIVE_SET_BOOTS = create("exclusive_set/boots");
|
||||
public static final Tag<Enchantment> EXCLUSIVE_SET_BOW = create("exclusive_set/bow");
|
||||
public static final Tag<Enchantment> EXCLUSIVE_SET_CROSSBOW = create("exclusive_set/crossbow");
|
||||
public static final Tag<Enchantment> EXCLUSIVE_SET_DAMAGE = create("exclusive_set/damage");
|
||||
public static final Tag<Enchantment> EXCLUSIVE_SET_MINING = create("exclusive_set/mining");
|
||||
public static final Tag<Enchantment> EXCLUSIVE_SET_RIPTIDE = create("exclusive_set/riptide");
|
||||
public static final Tag<Enchantment> TRADEABLE = create("tradeable");
|
||||
public static final Tag<Enchantment> DOUBLE_TRADE_PRICE = create("double_trade_price");
|
||||
public static final Tag<Enchantment> IN_ENCHANTING_TABLE = create("in_enchanting_table");
|
||||
public static final Tag<Enchantment> ON_MOB_SPAWN_EQUIPMENT = create("on_mob_spawn_equipment");
|
||||
public static final Tag<Enchantment> ON_TRADED_EQUIPMENT = create("on_traded_equipment");
|
||||
public static final Tag<Enchantment> ON_RANDOM_LOOT = create("on_random_loot");
|
||||
public static final Tag<Enchantment> CURSE = create("curse");
|
||||
public static final Tag<Enchantment> SMELTS_LOOT = create("smelts_loot");
|
||||
public static final Tag<Enchantment> PREVENTS_BEE_SPAWNS_WHEN_MINING = create("prevents_bee_spawns_when_mining");
|
||||
public static final Tag<Enchantment> PREVENTS_DECORATED_POT_SHATTERING = create("prevents_decorated_pot_shattering");
|
||||
public static final Tag<Enchantment> PREVENTS_ICE_MELTING = create("prevents_ice_melting");
|
||||
public static final Tag<Enchantment> PREVENTS_INFESTED_SPAWNS = create("prevents_infested_spawns");
|
||||
public static final Tag<Enchantment> TREASURE = create("treasure");
|
||||
public static final Tag<Enchantment> NON_TREASURE = create("non_treasure");
|
||||
public static final Tag<Enchantment> TRADES_DESERT_COMMON = create("trades/desert_common");
|
||||
public static final Tag<Enchantment> TRADES_JUNGLE_COMMON = create("trades/jungle_common");
|
||||
public static final Tag<Enchantment> TRADES_PLAINS_COMMON = create("trades/plains_common");
|
||||
public static final Tag<Enchantment> TRADES_SAVANNA_COMMON = create("trades/savanna_common");
|
||||
public static final Tag<Enchantment> TRADES_SNOW_COMMON = create("trades/snow_common");
|
||||
public static final Tag<Enchantment> TRADES_SWAMP_COMMON = create("trades/swamp_common");
|
||||
public static final Tag<Enchantment> TRADES_TAIGA_COMMON = create("trades/taiga_common");
|
||||
public static final Tag<Enchantment> TRADES_DESERT_SPECIAL = create("trades/desert_special");
|
||||
public static final Tag<Enchantment> TRADES_JUNGLE_SPECIAL = create("trades/jungle_special");
|
||||
public static final Tag<Enchantment> TRADES_PLAINS_SPECIAL = create("trades/plains_special");
|
||||
public static final Tag<Enchantment> TRADES_SAVANNA_SPECIAL = create("trades/savanna_special");
|
||||
public static final Tag<Enchantment> TRADES_SNOW_SPECIAL = create("trades/snow_special");
|
||||
public static final Tag<Enchantment> TRADES_SWAMP_SPECIAL = create("trades/swamp_special");
|
||||
public static final Tag<Enchantment> TRADES_TAIGA_SPECIAL = create("trades/taiga_special");
|
||||
|
||||
public static final EnchantmentTag TOOLTIP_ORDER = new EnchantmentTag("tooltip_order");
|
||||
public static final EnchantmentTag EXCLUSIVE_SET_ARMOR = new EnchantmentTag("exclusive_set/armor");
|
||||
public static final EnchantmentTag EXCLUSIVE_SET_BOOTS = new EnchantmentTag("exclusive_set/boots");
|
||||
public static final EnchantmentTag EXCLUSIVE_SET_BOW = new EnchantmentTag("exclusive_set/bow");
|
||||
public static final EnchantmentTag EXCLUSIVE_SET_CROSSBOW = new EnchantmentTag("exclusive_set/crossbow");
|
||||
public static final EnchantmentTag EXCLUSIVE_SET_DAMAGE = new EnchantmentTag("exclusive_set/damage");
|
||||
public static final EnchantmentTag EXCLUSIVE_SET_MINING = new EnchantmentTag("exclusive_set/mining");
|
||||
public static final EnchantmentTag EXCLUSIVE_SET_RIPTIDE = new EnchantmentTag("exclusive_set/riptide");
|
||||
public static final EnchantmentTag TRADEABLE = new EnchantmentTag("tradeable");
|
||||
public static final EnchantmentTag DOUBLE_TRADE_PRICE = new EnchantmentTag("double_trade_price");
|
||||
public static final EnchantmentTag IN_ENCHANTING_TABLE = new EnchantmentTag("in_enchanting_table");
|
||||
public static final EnchantmentTag ON_MOB_SPAWN_EQUIPMENT = new EnchantmentTag("on_mob_spawn_equipment");
|
||||
public static final EnchantmentTag ON_TRADED_EQUIPMENT = new EnchantmentTag("on_traded_equipment");
|
||||
public static final EnchantmentTag ON_RANDOM_LOOT = new EnchantmentTag("on_random_loot");
|
||||
public static final EnchantmentTag CURSE = new EnchantmentTag("curse");
|
||||
public static final EnchantmentTag SMELTS_LOOT = new EnchantmentTag("smelts_loot");
|
||||
public static final EnchantmentTag PREVENTS_BEE_SPAWNS_WHEN_MINING = new EnchantmentTag("prevents_bee_spawns_when_mining");
|
||||
public static final EnchantmentTag PREVENTS_DECORATED_POT_SHATTERING = new EnchantmentTag("prevents_decorated_pot_shattering");
|
||||
public static final EnchantmentTag PREVENTS_ICE_MELTING = new EnchantmentTag("prevents_ice_melting");
|
||||
public static final EnchantmentTag PREVENTS_INFESTED_SPAWNS = new EnchantmentTag("prevents_infested_spawns");
|
||||
public static final EnchantmentTag TREASURE = new EnchantmentTag("treasure");
|
||||
public static final EnchantmentTag NON_TREASURE = new EnchantmentTag("non_treasure");
|
||||
public static final EnchantmentTag TRADES_DESERT_COMMON = new EnchantmentTag("trades/desert_common");
|
||||
public static final EnchantmentTag TRADES_JUNGLE_COMMON = new EnchantmentTag("trades/jungle_common");
|
||||
public static final EnchantmentTag TRADES_PLAINS_COMMON = new EnchantmentTag("trades/plains_common");
|
||||
public static final EnchantmentTag TRADES_SAVANNA_COMMON = new EnchantmentTag("trades/savanna_common");
|
||||
public static final EnchantmentTag TRADES_SNOW_COMMON = new EnchantmentTag("trades/snow_common");
|
||||
public static final EnchantmentTag TRADES_SWAMP_COMMON = new EnchantmentTag("trades/swamp_common");
|
||||
public static final EnchantmentTag TRADES_TAIGA_COMMON = new EnchantmentTag("trades/taiga_common");
|
||||
public static final EnchantmentTag TRADES_DESERT_SPECIAL = new EnchantmentTag("trades/desert_special");
|
||||
public static final EnchantmentTag TRADES_JUNGLE_SPECIAL = new EnchantmentTag("trades/jungle_special");
|
||||
public static final EnchantmentTag TRADES_PLAINS_SPECIAL = new EnchantmentTag("trades/plains_special");
|
||||
public static final EnchantmentTag TRADES_SAVANNA_SPECIAL = new EnchantmentTag("trades/savanna_special");
|
||||
public static final EnchantmentTag TRADES_SNOW_SPECIAL = new EnchantmentTag("trades/snow_special");
|
||||
public static final EnchantmentTag TRADES_SWAMP_SPECIAL = new EnchantmentTag("trades/swamp_special");
|
||||
public static final EnchantmentTag TRADES_TAIGA_SPECIAL = new EnchantmentTag("trades/taiga_special");
|
||||
private EnchantmentTag() {}
|
||||
|
||||
private final int id;
|
||||
|
||||
private EnchantmentTag(String identifier) {
|
||||
this.id = ALL_ENCHANTMENT_TAGS.size();
|
||||
register(identifier, this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int ordinal() {
|
||||
return id;
|
||||
}
|
||||
|
||||
private static void register(String name, EnchantmentTag tag) {
|
||||
ALL_ENCHANTMENT_TAGS.put(MinecraftKey.key(name), tag);
|
||||
private static Tag<Enchantment> create(String name) {
|
||||
return new Tag<>(JavaRegistries.ENCHANTMENT, MinecraftKey.key(name));
|
||||
}
|
||||
}
|
||||
|
118
core/src/main/java/org/geysermc/geyser/session/cache/tags/GeyserHolderSet.java
vendored
Normale Datei
118
core/src/main/java/org/geysermc/geyser/session/cache/tags/GeyserHolderSet.java
vendored
Normale Datei
@ -0,0 +1,118 @@
|
||||
/*
|
||||
* Copyright (c) 2024 GeyserMC. http://geysermc.org
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*
|
||||
* @author GeyserMC
|
||||
* @link https://github.com/GeyserMC/Geyser
|
||||
*/
|
||||
|
||||
package org.geysermc.geyser.session.cache.tags;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
import java.util.function.ToIntFunction;
|
||||
|
||||
import it.unimi.dsi.fastutil.ints.IntArrays;
|
||||
import lombok.Data;
|
||||
import net.kyori.adventure.key.Key;
|
||||
import org.checkerframework.checker.nullness.qual.NonNull;
|
||||
import org.checkerframework.checker.nullness.qual.Nullable;
|
||||
import org.geysermc.geyser.session.GeyserSession;
|
||||
import org.geysermc.geyser.session.cache.TagCache;
|
||||
import org.geysermc.geyser.session.cache.registry.JavaRegistryKey;
|
||||
|
||||
/**
|
||||
* Similar to vanilla Minecraft's HolderSets, stores either a tag or a list of IDs (this list can also be represented as a single ID in vanilla HolderSets).
|
||||
*
|
||||
* <p>Because HolderSets utilise tags, when loading a HolderSet, Geyser must store tags for the registry the HolderSet is for (see {@link JavaRegistryKey}).</p>
|
||||
*
|
||||
* <p>Use the {@link GeyserHolderSet#readHolderSet} method to easily read a HolderSet from NBT sent by a server. To turn the HolderSet into a list of network IDs, use the {@link GeyserHolderSet#resolveRaw} method.
|
||||
* To turn the HolderSet into a list of objects, use the {@link GeyserHolderSet#resolve} method.</p>
|
||||
*/
|
||||
@Data
|
||||
public final class GeyserHolderSet<T> {
|
||||
|
||||
private final JavaRegistryKey<T> registry;
|
||||
private final @Nullable Tag<T> tag;
|
||||
private final int @Nullable [] holders;
|
||||
|
||||
public GeyserHolderSet(JavaRegistryKey<T> registry, int @NonNull [] holders) {
|
||||
this.registry = registry;
|
||||
this.tag = null;
|
||||
this.holders = holders;
|
||||
}
|
||||
|
||||
public GeyserHolderSet(JavaRegistryKey<T> registry, @NonNull Tag<T> tagId) {
|
||||
this.registry = registry;
|
||||
this.tag = tagId;
|
||||
this.holders = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Resolves the HolderSet, and automatically maps the network IDs to their respective object types. If the HolderSet is a list of IDs, this will be returned. If it is a tag, the tag will be resolved from the tag cache.
|
||||
*
|
||||
* @return the HolderSet turned into a list of objects.
|
||||
*/
|
||||
public List<T> resolve(GeyserSession session) {
|
||||
return TagCache.mapRawArray(session, resolveRaw(session.getTagCache()), registry);
|
||||
}
|
||||
|
||||
/**
|
||||
* Resolves the HolderSet. If the HolderSet is a list of IDs, this will be returned. If it is a tag, the tag will be resolved from the tag cache.
|
||||
*
|
||||
* @return the HolderSet turned into a list of objects.
|
||||
*/
|
||||
public int[] resolveRaw(TagCache tagCache) {
|
||||
if (holders != null) {
|
||||
return holders;
|
||||
}
|
||||
|
||||
return tagCache.getRaw(Objects.requireNonNull(tag, "HolderSet must have a tag if it doesn't have a list of IDs"));
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads a HolderSet from an object from NBT.
|
||||
*
|
||||
* @param session session, only used for logging purposes.
|
||||
* @param registry the registry the HolderSet contains IDs from.
|
||||
* @param holderSet the HolderSet as an object from NBT.
|
||||
* @param keyIdMapping a function that maps resource location IDs in the HolderSet's registry to their network IDs.
|
||||
*/
|
||||
public static <T> GeyserHolderSet<T> readHolderSet(GeyserSession session, JavaRegistryKey<T> registry, @Nullable Object holderSet, ToIntFunction<Key> keyIdMapping) {
|
||||
if (holderSet == null) {
|
||||
return new GeyserHolderSet<>(registry, IntArrays.EMPTY_ARRAY);
|
||||
}
|
||||
|
||||
if (holderSet instanceof String stringTag) {
|
||||
if (stringTag.startsWith("#")) {
|
||||
// Tag
|
||||
return new GeyserHolderSet<>(registry, new Tag<>(registry, Key.key(stringTag.substring(1)))); // Remove '#' at beginning that indicates tag
|
||||
} else if (stringTag.isEmpty()) {
|
||||
return new GeyserHolderSet<>(registry, IntArrays.EMPTY_ARRAY);
|
||||
}
|
||||
return new GeyserHolderSet<>(registry, new int[]{keyIdMapping.applyAsInt(Key.key(stringTag))});
|
||||
} else if (holderSet instanceof List<?> list) {
|
||||
// Assume the list is a list of strings
|
||||
return new GeyserHolderSet<>(registry, list.stream().map(o -> (String) o).map(Key::key).mapToInt(keyIdMapping).toArray());
|
||||
}
|
||||
session.getGeyser().getLogger().warning("Failed parsing HolderSet for registry + " + registry + "! Expected either a tag, a string ID or a list of string IDs, found " + holderSet);
|
||||
return new GeyserHolderSet<>(registry, IntArrays.EMPTY_ARRAY);
|
||||
}
|
||||
}
|
@ -25,178 +25,166 @@
|
||||
|
||||
package org.geysermc.geyser.session.cache.tags;
|
||||
|
||||
import net.kyori.adventure.key.Key;
|
||||
import org.geysermc.geyser.item.type.Item;
|
||||
import org.geysermc.geyser.session.cache.registry.JavaRegistries;
|
||||
import org.geysermc.geyser.util.MinecraftKey;
|
||||
import org.geysermc.geyser.util.Ordered;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* Lists vanilla item tags.
|
||||
*/
|
||||
@SuppressWarnings("unused")
|
||||
public final class ItemTag implements Ordered {
|
||||
public static final Map<Key, ItemTag> ALL_ITEM_TAGS = new HashMap<>();
|
||||
public final class ItemTag {
|
||||
public static final Tag<Item> WOOL = create("wool");
|
||||
public static final Tag<Item> PLANKS = create("planks");
|
||||
public static final Tag<Item> STONE_BRICKS = create("stone_bricks");
|
||||
public static final Tag<Item> WOODEN_BUTTONS = create("wooden_buttons");
|
||||
public static final Tag<Item> STONE_BUTTONS = create("stone_buttons");
|
||||
public static final Tag<Item> BUTTONS = create("buttons");
|
||||
public static final Tag<Item> WOOL_CARPETS = create("wool_carpets");
|
||||
public static final Tag<Item> WOODEN_DOORS = create("wooden_doors");
|
||||
public static final Tag<Item> WOODEN_STAIRS = create("wooden_stairs");
|
||||
public static final Tag<Item> WOODEN_SLABS = create("wooden_slabs");
|
||||
public static final Tag<Item> WOODEN_FENCES = create("wooden_fences");
|
||||
public static final Tag<Item> FENCE_GATES = create("fence_gates");
|
||||
public static final Tag<Item> WOODEN_PRESSURE_PLATES = create("wooden_pressure_plates");
|
||||
public static final Tag<Item> WOODEN_TRAPDOORS = create("wooden_trapdoors");
|
||||
public static final Tag<Item> DOORS = create("doors");
|
||||
public static final Tag<Item> SAPLINGS = create("saplings");
|
||||
public static final Tag<Item> LOGS_THAT_BURN = create("logs_that_burn");
|
||||
public static final Tag<Item> LOGS = create("logs");
|
||||
public static final Tag<Item> DARK_OAK_LOGS = create("dark_oak_logs");
|
||||
public static final Tag<Item> OAK_LOGS = create("oak_logs");
|
||||
public static final Tag<Item> BIRCH_LOGS = create("birch_logs");
|
||||
public static final Tag<Item> ACACIA_LOGS = create("acacia_logs");
|
||||
public static final Tag<Item> CHERRY_LOGS = create("cherry_logs");
|
||||
public static final Tag<Item> JUNGLE_LOGS = create("jungle_logs");
|
||||
public static final Tag<Item> SPRUCE_LOGS = create("spruce_logs");
|
||||
public static final Tag<Item> MANGROVE_LOGS = create("mangrove_logs");
|
||||
public static final Tag<Item> CRIMSON_STEMS = create("crimson_stems");
|
||||
public static final Tag<Item> WARPED_STEMS = create("warped_stems");
|
||||
public static final Tag<Item> BAMBOO_BLOCKS = create("bamboo_blocks");
|
||||
public static final Tag<Item> WART_BLOCKS = create("wart_blocks");
|
||||
public static final Tag<Item> BANNERS = create("banners");
|
||||
public static final Tag<Item> SAND = create("sand");
|
||||
public static final Tag<Item> SMELTS_TO_GLASS = create("smelts_to_glass");
|
||||
public static final Tag<Item> STAIRS = create("stairs");
|
||||
public static final Tag<Item> SLABS = create("slabs");
|
||||
public static final Tag<Item> WALLS = create("walls");
|
||||
public static final Tag<Item> ANVIL = create("anvil");
|
||||
public static final Tag<Item> RAILS = create("rails");
|
||||
public static final Tag<Item> LEAVES = create("leaves");
|
||||
public static final Tag<Item> TRAPDOORS = create("trapdoors");
|
||||
public static final Tag<Item> SMALL_FLOWERS = create("small_flowers");
|
||||
public static final Tag<Item> BEDS = create("beds");
|
||||
public static final Tag<Item> FENCES = create("fences");
|
||||
public static final Tag<Item> TALL_FLOWERS = create("tall_flowers");
|
||||
public static final Tag<Item> FLOWERS = create("flowers");
|
||||
public static final Tag<Item> PIGLIN_REPELLENTS = create("piglin_repellents");
|
||||
public static final Tag<Item> PIGLIN_LOVED = create("piglin_loved");
|
||||
public static final Tag<Item> IGNORED_BY_PIGLIN_BABIES = create("ignored_by_piglin_babies");
|
||||
public static final Tag<Item> MEAT = create("meat");
|
||||
public static final Tag<Item> SNIFFER_FOOD = create("sniffer_food");
|
||||
public static final Tag<Item> PIGLIN_FOOD = create("piglin_food");
|
||||
public static final Tag<Item> FOX_FOOD = create("fox_food");
|
||||
public static final Tag<Item> COW_FOOD = create("cow_food");
|
||||
public static final Tag<Item> GOAT_FOOD = create("goat_food");
|
||||
public static final Tag<Item> SHEEP_FOOD = create("sheep_food");
|
||||
public static final Tag<Item> WOLF_FOOD = create("wolf_food");
|
||||
public static final Tag<Item> CAT_FOOD = create("cat_food");
|
||||
public static final Tag<Item> HORSE_FOOD = create("horse_food");
|
||||
public static final Tag<Item> HORSE_TEMPT_ITEMS = create("horse_tempt_items");
|
||||
public static final Tag<Item> CAMEL_FOOD = create("camel_food");
|
||||
public static final Tag<Item> ARMADILLO_FOOD = create("armadillo_food");
|
||||
public static final Tag<Item> BEE_FOOD = create("bee_food");
|
||||
public static final Tag<Item> CHICKEN_FOOD = create("chicken_food");
|
||||
public static final Tag<Item> FROG_FOOD = create("frog_food");
|
||||
public static final Tag<Item> HOGLIN_FOOD = create("hoglin_food");
|
||||
public static final Tag<Item> LLAMA_FOOD = create("llama_food");
|
||||
public static final Tag<Item> LLAMA_TEMPT_ITEMS = create("llama_tempt_items");
|
||||
public static final Tag<Item> OCELOT_FOOD = create("ocelot_food");
|
||||
public static final Tag<Item> PANDA_FOOD = create("panda_food");
|
||||
public static final Tag<Item> PIG_FOOD = create("pig_food");
|
||||
public static final Tag<Item> RABBIT_FOOD = create("rabbit_food");
|
||||
public static final Tag<Item> STRIDER_FOOD = create("strider_food");
|
||||
public static final Tag<Item> STRIDER_TEMPT_ITEMS = create("strider_tempt_items");
|
||||
public static final Tag<Item> TURTLE_FOOD = create("turtle_food");
|
||||
public static final Tag<Item> PARROT_FOOD = create("parrot_food");
|
||||
public static final Tag<Item> PARROT_POISONOUS_FOOD = create("parrot_poisonous_food");
|
||||
public static final Tag<Item> AXOLOTL_FOOD = create("axolotl_food");
|
||||
public static final Tag<Item> GOLD_ORES = create("gold_ores");
|
||||
public static final Tag<Item> IRON_ORES = create("iron_ores");
|
||||
public static final Tag<Item> DIAMOND_ORES = create("diamond_ores");
|
||||
public static final Tag<Item> REDSTONE_ORES = create("redstone_ores");
|
||||
public static final Tag<Item> LAPIS_ORES = create("lapis_ores");
|
||||
public static final Tag<Item> COAL_ORES = create("coal_ores");
|
||||
public static final Tag<Item> EMERALD_ORES = create("emerald_ores");
|
||||
public static final Tag<Item> COPPER_ORES = create("copper_ores");
|
||||
public static final Tag<Item> NON_FLAMMABLE_WOOD = create("non_flammable_wood");
|
||||
public static final Tag<Item> SOUL_FIRE_BASE_BLOCKS = create("soul_fire_base_blocks");
|
||||
public static final Tag<Item> CANDLES = create("candles");
|
||||
public static final Tag<Item> DIRT = create("dirt");
|
||||
public static final Tag<Item> TERRACOTTA = create("terracotta");
|
||||
public static final Tag<Item> COMPLETES_FIND_TREE_TUTORIAL = create("completes_find_tree_tutorial");
|
||||
public static final Tag<Item> BOATS = create("boats");
|
||||
public static final Tag<Item> CHEST_BOATS = create("chest_boats");
|
||||
public static final Tag<Item> FISHES = create("fishes");
|
||||
public static final Tag<Item> SIGNS = create("signs");
|
||||
public static final Tag<Item> CREEPER_DROP_MUSIC_DISCS = create("creeper_drop_music_discs");
|
||||
public static final Tag<Item> COALS = create("coals");
|
||||
public static final Tag<Item> ARROWS = create("arrows");
|
||||
public static final Tag<Item> LECTERN_BOOKS = create("lectern_books");
|
||||
public static final Tag<Item> BOOKSHELF_BOOKS = create("bookshelf_books");
|
||||
public static final Tag<Item> BEACON_PAYMENT_ITEMS = create("beacon_payment_items");
|
||||
public static final Tag<Item> STONE_TOOL_MATERIALS = create("stone_tool_materials");
|
||||
public static final Tag<Item> STONE_CRAFTING_MATERIALS = create("stone_crafting_materials");
|
||||
public static final Tag<Item> FREEZE_IMMUNE_WEARABLES = create("freeze_immune_wearables");
|
||||
public static final Tag<Item> DAMPENS_VIBRATIONS = create("dampens_vibrations");
|
||||
public static final Tag<Item> CLUSTER_MAX_HARVESTABLES = create("cluster_max_harvestables");
|
||||
public static final Tag<Item> COMPASSES = create("compasses");
|
||||
public static final Tag<Item> HANGING_SIGNS = create("hanging_signs");
|
||||
public static final Tag<Item> CREEPER_IGNITERS = create("creeper_igniters");
|
||||
public static final Tag<Item> NOTEBLOCK_TOP_INSTRUMENTS = create("noteblock_top_instruments");
|
||||
public static final Tag<Item> FOOT_ARMOR = create("foot_armor");
|
||||
public static final Tag<Item> LEG_ARMOR = create("leg_armor");
|
||||
public static final Tag<Item> CHEST_ARMOR = create("chest_armor");
|
||||
public static final Tag<Item> HEAD_ARMOR = create("head_armor");
|
||||
public static final Tag<Item> SKULLS = create("skulls");
|
||||
public static final Tag<Item> TRIMMABLE_ARMOR = create("trimmable_armor");
|
||||
public static final Tag<Item> TRIM_MATERIALS = create("trim_materials");
|
||||
public static final Tag<Item> TRIM_TEMPLATES = create("trim_templates");
|
||||
public static final Tag<Item> DECORATED_POT_SHERDS = create("decorated_pot_sherds");
|
||||
public static final Tag<Item> DECORATED_POT_INGREDIENTS = create("decorated_pot_ingredients");
|
||||
public static final Tag<Item> SWORDS = create("swords");
|
||||
public static final Tag<Item> AXES = create("axes");
|
||||
public static final Tag<Item> HOES = create("hoes");
|
||||
public static final Tag<Item> PICKAXES = create("pickaxes");
|
||||
public static final Tag<Item> SHOVELS = create("shovels");
|
||||
public static final Tag<Item> BREAKS_DECORATED_POTS = create("breaks_decorated_pots");
|
||||
public static final Tag<Item> VILLAGER_PLANTABLE_SEEDS = create("villager_plantable_seeds");
|
||||
public static final Tag<Item> DYEABLE = create("dyeable");
|
||||
public static final Tag<Item> ENCHANTABLE_FOOT_ARMOR = create("enchantable/foot_armor");
|
||||
public static final Tag<Item> ENCHANTABLE_LEG_ARMOR = create("enchantable/leg_armor");
|
||||
public static final Tag<Item> ENCHANTABLE_CHEST_ARMOR = create("enchantable/chest_armor");
|
||||
public static final Tag<Item> ENCHANTABLE_HEAD_ARMOR = create("enchantable/head_armor");
|
||||
public static final Tag<Item> ENCHANTABLE_ARMOR = create("enchantable/armor");
|
||||
public static final Tag<Item> ENCHANTABLE_SWORD = create("enchantable/sword");
|
||||
public static final Tag<Item> ENCHANTABLE_FIRE_ASPECT = create("enchantable/fire_aspect");
|
||||
public static final Tag<Item> ENCHANTABLE_SHARP_WEAPON = create("enchantable/sharp_weapon");
|
||||
public static final Tag<Item> ENCHANTABLE_WEAPON = create("enchantable/weapon");
|
||||
public static final Tag<Item> ENCHANTABLE_MINING = create("enchantable/mining");
|
||||
public static final Tag<Item> ENCHANTABLE_MINING_LOOT = create("enchantable/mining_loot");
|
||||
public static final Tag<Item> ENCHANTABLE_FISHING = create("enchantable/fishing");
|
||||
public static final Tag<Item> ENCHANTABLE_TRIDENT = create("enchantable/trident");
|
||||
public static final Tag<Item> ENCHANTABLE_DURABILITY = create("enchantable/durability");
|
||||
public static final Tag<Item> ENCHANTABLE_BOW = create("enchantable/bow");
|
||||
public static final Tag<Item> ENCHANTABLE_EQUIPPABLE = create("enchantable/equippable");
|
||||
public static final Tag<Item> ENCHANTABLE_CROSSBOW = create("enchantable/crossbow");
|
||||
public static final Tag<Item> ENCHANTABLE_VANISHING = create("enchantable/vanishing");
|
||||
public static final Tag<Item> ENCHANTABLE_MACE = create("enchantable/mace");
|
||||
|
||||
public static final ItemTag WOOL = new ItemTag("wool");
|
||||
public static final ItemTag PLANKS = new ItemTag("planks");
|
||||
public static final ItemTag STONE_BRICKS = new ItemTag("stone_bricks");
|
||||
public static final ItemTag WOODEN_BUTTONS = new ItemTag("wooden_buttons");
|
||||
public static final ItemTag STONE_BUTTONS = new ItemTag("stone_buttons");
|
||||
public static final ItemTag BUTTONS = new ItemTag("buttons");
|
||||
public static final ItemTag WOOL_CARPETS = new ItemTag("wool_carpets");
|
||||
public static final ItemTag WOODEN_DOORS = new ItemTag("wooden_doors");
|
||||
public static final ItemTag WOODEN_STAIRS = new ItemTag("wooden_stairs");
|
||||
public static final ItemTag WOODEN_SLABS = new ItemTag("wooden_slabs");
|
||||
public static final ItemTag WOODEN_FENCES = new ItemTag("wooden_fences");
|
||||
public static final ItemTag FENCE_GATES = new ItemTag("fence_gates");
|
||||
public static final ItemTag WOODEN_PRESSURE_PLATES = new ItemTag("wooden_pressure_plates");
|
||||
public static final ItemTag WOODEN_TRAPDOORS = new ItemTag("wooden_trapdoors");
|
||||
public static final ItemTag DOORS = new ItemTag("doors");
|
||||
public static final ItemTag SAPLINGS = new ItemTag("saplings");
|
||||
public static final ItemTag LOGS_THAT_BURN = new ItemTag("logs_that_burn");
|
||||
public static final ItemTag LOGS = new ItemTag("logs");
|
||||
public static final ItemTag DARK_OAK_LOGS = new ItemTag("dark_oak_logs");
|
||||
public static final ItemTag OAK_LOGS = new ItemTag("oak_logs");
|
||||
public static final ItemTag BIRCH_LOGS = new ItemTag("birch_logs");
|
||||
public static final ItemTag ACACIA_LOGS = new ItemTag("acacia_logs");
|
||||
public static final ItemTag CHERRY_LOGS = new ItemTag("cherry_logs");
|
||||
public static final ItemTag JUNGLE_LOGS = new ItemTag("jungle_logs");
|
||||
public static final ItemTag SPRUCE_LOGS = new ItemTag("spruce_logs");
|
||||
public static final ItemTag MANGROVE_LOGS = new ItemTag("mangrove_logs");
|
||||
public static final ItemTag CRIMSON_STEMS = new ItemTag("crimson_stems");
|
||||
public static final ItemTag WARPED_STEMS = new ItemTag("warped_stems");
|
||||
public static final ItemTag BAMBOO_BLOCKS = new ItemTag("bamboo_blocks");
|
||||
public static final ItemTag WART_BLOCKS = new ItemTag("wart_blocks");
|
||||
public static final ItemTag BANNERS = new ItemTag("banners");
|
||||
public static final ItemTag SAND = new ItemTag("sand");
|
||||
public static final ItemTag SMELTS_TO_GLASS = new ItemTag("smelts_to_glass");
|
||||
public static final ItemTag STAIRS = new ItemTag("stairs");
|
||||
public static final ItemTag SLABS = new ItemTag("slabs");
|
||||
public static final ItemTag WALLS = new ItemTag("walls");
|
||||
public static final ItemTag ANVIL = new ItemTag("anvil");
|
||||
public static final ItemTag RAILS = new ItemTag("rails");
|
||||
public static final ItemTag LEAVES = new ItemTag("leaves");
|
||||
public static final ItemTag TRAPDOORS = new ItemTag("trapdoors");
|
||||
public static final ItemTag SMALL_FLOWERS = new ItemTag("small_flowers");
|
||||
public static final ItemTag BEDS = new ItemTag("beds");
|
||||
public static final ItemTag FENCES = new ItemTag("fences");
|
||||
public static final ItemTag TALL_FLOWERS = new ItemTag("tall_flowers");
|
||||
public static final ItemTag FLOWERS = new ItemTag("flowers");
|
||||
public static final ItemTag PIGLIN_REPELLENTS = new ItemTag("piglin_repellents");
|
||||
public static final ItemTag PIGLIN_LOVED = new ItemTag("piglin_loved");
|
||||
public static final ItemTag IGNORED_BY_PIGLIN_BABIES = new ItemTag("ignored_by_piglin_babies");
|
||||
public static final ItemTag MEAT = new ItemTag("meat");
|
||||
public static final ItemTag SNIFFER_FOOD = new ItemTag("sniffer_food");
|
||||
public static final ItemTag PIGLIN_FOOD = new ItemTag("piglin_food");
|
||||
public static final ItemTag FOX_FOOD = new ItemTag("fox_food");
|
||||
public static final ItemTag COW_FOOD = new ItemTag("cow_food");
|
||||
public static final ItemTag GOAT_FOOD = new ItemTag("goat_food");
|
||||
public static final ItemTag SHEEP_FOOD = new ItemTag("sheep_food");
|
||||
public static final ItemTag WOLF_FOOD = new ItemTag("wolf_food");
|
||||
public static final ItemTag CAT_FOOD = new ItemTag("cat_food");
|
||||
public static final ItemTag HORSE_FOOD = new ItemTag("horse_food");
|
||||
public static final ItemTag HORSE_TEMPT_ITEMS = new ItemTag("horse_tempt_items");
|
||||
public static final ItemTag CAMEL_FOOD = new ItemTag("camel_food");
|
||||
public static final ItemTag ARMADILLO_FOOD = new ItemTag("armadillo_food");
|
||||
public static final ItemTag BEE_FOOD = new ItemTag("bee_food");
|
||||
public static final ItemTag CHICKEN_FOOD = new ItemTag("chicken_food");
|
||||
public static final ItemTag FROG_FOOD = new ItemTag("frog_food");
|
||||
public static final ItemTag HOGLIN_FOOD = new ItemTag("hoglin_food");
|
||||
public static final ItemTag LLAMA_FOOD = new ItemTag("llama_food");
|
||||
public static final ItemTag LLAMA_TEMPT_ITEMS = new ItemTag("llama_tempt_items");
|
||||
public static final ItemTag OCELOT_FOOD = new ItemTag("ocelot_food");
|
||||
public static final ItemTag PANDA_FOOD = new ItemTag("panda_food");
|
||||
public static final ItemTag PIG_FOOD = new ItemTag("pig_food");
|
||||
public static final ItemTag RABBIT_FOOD = new ItemTag("rabbit_food");
|
||||
public static final ItemTag STRIDER_FOOD = new ItemTag("strider_food");
|
||||
public static final ItemTag STRIDER_TEMPT_ITEMS = new ItemTag("strider_tempt_items");
|
||||
public static final ItemTag TURTLE_FOOD = new ItemTag("turtle_food");
|
||||
public static final ItemTag PARROT_FOOD = new ItemTag("parrot_food");
|
||||
public static final ItemTag PARROT_POISONOUS_FOOD = new ItemTag("parrot_poisonous_food");
|
||||
public static final ItemTag AXOLOTL_FOOD = new ItemTag("axolotl_food");
|
||||
public static final ItemTag GOLD_ORES = new ItemTag("gold_ores");
|
||||
public static final ItemTag IRON_ORES = new ItemTag("iron_ores");
|
||||
public static final ItemTag DIAMOND_ORES = new ItemTag("diamond_ores");
|
||||
public static final ItemTag REDSTONE_ORES = new ItemTag("redstone_ores");
|
||||
public static final ItemTag LAPIS_ORES = new ItemTag("lapis_ores");
|
||||
public static final ItemTag COAL_ORES = new ItemTag("coal_ores");
|
||||
public static final ItemTag EMERALD_ORES = new ItemTag("emerald_ores");
|
||||
public static final ItemTag COPPER_ORES = new ItemTag("copper_ores");
|
||||
public static final ItemTag NON_FLAMMABLE_WOOD = new ItemTag("non_flammable_wood");
|
||||
public static final ItemTag SOUL_FIRE_BASE_BLOCKS = new ItemTag("soul_fire_base_blocks");
|
||||
public static final ItemTag CANDLES = new ItemTag("candles");
|
||||
public static final ItemTag DIRT = new ItemTag("dirt");
|
||||
public static final ItemTag TERRACOTTA = new ItemTag("terracotta");
|
||||
public static final ItemTag COMPLETES_FIND_TREE_TUTORIAL = new ItemTag("completes_find_tree_tutorial");
|
||||
public static final ItemTag BOATS = new ItemTag("boats");
|
||||
public static final ItemTag CHEST_BOATS = new ItemTag("chest_boats");
|
||||
public static final ItemTag FISHES = new ItemTag("fishes");
|
||||
public static final ItemTag SIGNS = new ItemTag("signs");
|
||||
public static final ItemTag CREEPER_DROP_MUSIC_DISCS = new ItemTag("creeper_drop_music_discs");
|
||||
public static final ItemTag COALS = new ItemTag("coals");
|
||||
public static final ItemTag ARROWS = new ItemTag("arrows");
|
||||
public static final ItemTag LECTERN_BOOKS = new ItemTag("lectern_books");
|
||||
public static final ItemTag BOOKSHELF_BOOKS = new ItemTag("bookshelf_books");
|
||||
public static final ItemTag BEACON_PAYMENT_ITEMS = new ItemTag("beacon_payment_items");
|
||||
public static final ItemTag STONE_TOOL_MATERIALS = new ItemTag("stone_tool_materials");
|
||||
public static final ItemTag STONE_CRAFTING_MATERIALS = new ItemTag("stone_crafting_materials");
|
||||
public static final ItemTag FREEZE_IMMUNE_WEARABLES = new ItemTag("freeze_immune_wearables");
|
||||
public static final ItemTag DAMPENS_VIBRATIONS = new ItemTag("dampens_vibrations");
|
||||
public static final ItemTag CLUSTER_MAX_HARVESTABLES = new ItemTag("cluster_max_harvestables");
|
||||
public static final ItemTag COMPASSES = new ItemTag("compasses");
|
||||
public static final ItemTag HANGING_SIGNS = new ItemTag("hanging_signs");
|
||||
public static final ItemTag CREEPER_IGNITERS = new ItemTag("creeper_igniters");
|
||||
public static final ItemTag NOTEBLOCK_TOP_INSTRUMENTS = new ItemTag("noteblock_top_instruments");
|
||||
public static final ItemTag FOOT_ARMOR = new ItemTag("foot_armor");
|
||||
public static final ItemTag LEG_ARMOR = new ItemTag("leg_armor");
|
||||
public static final ItemTag CHEST_ARMOR = new ItemTag("chest_armor");
|
||||
public static final ItemTag HEAD_ARMOR = new ItemTag("head_armor");
|
||||
public static final ItemTag SKULLS = new ItemTag("skulls");
|
||||
public static final ItemTag TRIMMABLE_ARMOR = new ItemTag("trimmable_armor");
|
||||
public static final ItemTag TRIM_MATERIALS = new ItemTag("trim_materials");
|
||||
public static final ItemTag TRIM_TEMPLATES = new ItemTag("trim_templates");
|
||||
public static final ItemTag DECORATED_POT_SHERDS = new ItemTag("decorated_pot_sherds");
|
||||
public static final ItemTag DECORATED_POT_INGREDIENTS = new ItemTag("decorated_pot_ingredients");
|
||||
public static final ItemTag SWORDS = new ItemTag("swords");
|
||||
public static final ItemTag AXES = new ItemTag("axes");
|
||||
public static final ItemTag HOES = new ItemTag("hoes");
|
||||
public static final ItemTag PICKAXES = new ItemTag("pickaxes");
|
||||
public static final ItemTag SHOVELS = new ItemTag("shovels");
|
||||
public static final ItemTag BREAKS_DECORATED_POTS = new ItemTag("breaks_decorated_pots");
|
||||
public static final ItemTag VILLAGER_PLANTABLE_SEEDS = new ItemTag("villager_plantable_seeds");
|
||||
public static final ItemTag DYEABLE = new ItemTag("dyeable");
|
||||
public static final ItemTag ENCHANTABLE_FOOT_ARMOR = new ItemTag("enchantable/foot_armor");
|
||||
public static final ItemTag ENCHANTABLE_LEG_ARMOR = new ItemTag("enchantable/leg_armor");
|
||||
public static final ItemTag ENCHANTABLE_CHEST_ARMOR = new ItemTag("enchantable/chest_armor");
|
||||
public static final ItemTag ENCHANTABLE_HEAD_ARMOR = new ItemTag("enchantable/head_armor");
|
||||
public static final ItemTag ENCHANTABLE_ARMOR = new ItemTag("enchantable/armor");
|
||||
public static final ItemTag ENCHANTABLE_SWORD = new ItemTag("enchantable/sword");
|
||||
public static final ItemTag ENCHANTABLE_FIRE_ASPECT = new ItemTag("enchantable/fire_aspect");
|
||||
public static final ItemTag ENCHANTABLE_SHARP_WEAPON = new ItemTag("enchantable/sharp_weapon");
|
||||
public static final ItemTag ENCHANTABLE_WEAPON = new ItemTag("enchantable/weapon");
|
||||
public static final ItemTag ENCHANTABLE_MINING = new ItemTag("enchantable/mining");
|
||||
public static final ItemTag ENCHANTABLE_MINING_LOOT = new ItemTag("enchantable/mining_loot");
|
||||
public static final ItemTag ENCHANTABLE_FISHING = new ItemTag("enchantable/fishing");
|
||||
public static final ItemTag ENCHANTABLE_TRIDENT = new ItemTag("enchantable/trident");
|
||||
public static final ItemTag ENCHANTABLE_DURABILITY = new ItemTag("enchantable/durability");
|
||||
public static final ItemTag ENCHANTABLE_BOW = new ItemTag("enchantable/bow");
|
||||
public static final ItemTag ENCHANTABLE_EQUIPPABLE = new ItemTag("enchantable/equippable");
|
||||
public static final ItemTag ENCHANTABLE_CROSSBOW = new ItemTag("enchantable/crossbow");
|
||||
public static final ItemTag ENCHANTABLE_VANISHING = new ItemTag("enchantable/vanishing");
|
||||
public static final ItemTag ENCHANTABLE_MACE = new ItemTag("enchantable/mace");
|
||||
private ItemTag() {}
|
||||
|
||||
private final int id;
|
||||
|
||||
private ItemTag(String identifier) {
|
||||
this.id = ALL_ITEM_TAGS.size();
|
||||
register(identifier, this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int ordinal() {
|
||||
return id;
|
||||
}
|
||||
|
||||
private static void register(String name, ItemTag tag) {
|
||||
ALL_ITEM_TAGS.put(MinecraftKey.key(name), tag);
|
||||
private static Tag<Item> create(String name) {
|
||||
return new Tag<>(JavaRegistries.ITEM, MinecraftKey.key(name));
|
||||
}
|
||||
}
|
||||
|
35
core/src/main/java/org/geysermc/geyser/session/cache/tags/Tag.java
vendored
Normale Datei
35
core/src/main/java/org/geysermc/geyser/session/cache/tags/Tag.java
vendored
Normale Datei
@ -0,0 +1,35 @@
|
||||
/*
|
||||
* Copyright (c) 2024 GeyserMC. http://geysermc.org
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*
|
||||
* @author GeyserMC
|
||||
* @link https://github.com/GeyserMC/Geyser
|
||||
*/
|
||||
|
||||
package org.geysermc.geyser.session.cache.tags;
|
||||
|
||||
import net.kyori.adventure.key.Key;
|
||||
import org.geysermc.geyser.session.cache.registry.JavaRegistryKey;
|
||||
|
||||
/**
|
||||
* A tag in any of the registries that tags are loaded for by Geyser.
|
||||
*/
|
||||
public record Tag<T>(JavaRegistryKey<T> registry, Key tag) {
|
||||
}
|
@ -25,21 +25,40 @@
|
||||
|
||||
package org.geysermc.geyser.translator.inventory;
|
||||
|
||||
import it.unimi.dsi.fastutil.ints.*;
|
||||
import it.unimi.dsi.fastutil.ints.Int2IntMap;
|
||||
import it.unimi.dsi.fastutil.ints.Int2IntOpenHashMap;
|
||||
import it.unimi.dsi.fastutil.ints.Int2ObjectMap;
|
||||
import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap;
|
||||
import it.unimi.dsi.fastutil.ints.IntIterator;
|
||||
import it.unimi.dsi.fastutil.ints.IntLinkedOpenHashSet;
|
||||
import it.unimi.dsi.fastutil.ints.IntOpenHashSet;
|
||||
import it.unimi.dsi.fastutil.ints.IntSet;
|
||||
import it.unimi.dsi.fastutil.ints.IntSortedSet;
|
||||
import lombok.AllArgsConstructor;
|
||||
import org.checkerframework.checker.nullness.qual.Nullable;
|
||||
import org.cloudburstmc.protocol.bedrock.data.inventory.ContainerSlotType;
|
||||
import org.cloudburstmc.protocol.bedrock.data.inventory.FullContainerName;
|
||||
import org.cloudburstmc.protocol.bedrock.data.inventory.itemstack.request.ItemStackRequest;
|
||||
import org.cloudburstmc.protocol.bedrock.data.inventory.itemstack.request.ItemStackRequestSlotData;
|
||||
import org.cloudburstmc.protocol.bedrock.data.inventory.itemstack.request.action.*;
|
||||
import org.cloudburstmc.protocol.bedrock.data.inventory.itemstack.request.action.AutoCraftRecipeAction;
|
||||
import org.cloudburstmc.protocol.bedrock.data.inventory.itemstack.request.action.ConsumeAction;
|
||||
import org.cloudburstmc.protocol.bedrock.data.inventory.itemstack.request.action.CraftResultsDeprecatedAction;
|
||||
import org.cloudburstmc.protocol.bedrock.data.inventory.itemstack.request.action.DropAction;
|
||||
import org.cloudburstmc.protocol.bedrock.data.inventory.itemstack.request.action.ItemStackRequestAction;
|
||||
import org.cloudburstmc.protocol.bedrock.data.inventory.itemstack.request.action.SwapAction;
|
||||
import org.cloudburstmc.protocol.bedrock.data.inventory.itemstack.request.action.TransferItemStackRequestAction;
|
||||
import org.cloudburstmc.protocol.bedrock.data.inventory.itemstack.response.ItemStackResponse;
|
||||
import org.cloudburstmc.protocol.bedrock.data.inventory.itemstack.response.ItemStackResponseContainer;
|
||||
import org.cloudburstmc.protocol.bedrock.data.inventory.itemstack.response.ItemStackResponseSlot;
|
||||
import org.cloudburstmc.protocol.bedrock.data.inventory.itemstack.response.ItemStackResponseStatus;
|
||||
import org.cloudburstmc.protocol.bedrock.packet.ItemStackResponsePacket;
|
||||
import org.geysermc.geyser.GeyserImpl;
|
||||
import org.geysermc.geyser.inventory.*;
|
||||
import org.geysermc.geyser.inventory.BedrockContainerSlot;
|
||||
import org.geysermc.geyser.inventory.CartographyContainer;
|
||||
import org.geysermc.geyser.inventory.GeyserItemStack;
|
||||
import org.geysermc.geyser.inventory.Inventory;
|
||||
import org.geysermc.geyser.inventory.PlayerInventory;
|
||||
import org.geysermc.geyser.inventory.SlotType;
|
||||
import org.geysermc.geyser.inventory.click.Click;
|
||||
import org.geysermc.geyser.inventory.click.ClickPlan;
|
||||
import org.geysermc.geyser.inventory.recipe.GeyserRecipe;
|
||||
@ -56,12 +75,17 @@ import org.geysermc.geyser.translator.inventory.furnace.SmokerInventoryTranslato
|
||||
import org.geysermc.geyser.util.InventoryUtils;
|
||||
import org.geysermc.geyser.util.ItemUtils;
|
||||
import org.geysermc.mcprotocollib.protocol.data.game.inventory.ContainerType;
|
||||
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.DataComponents;
|
||||
import org.geysermc.mcprotocollib.protocol.data.game.recipe.Ingredient;
|
||||
import org.geysermc.mcprotocollib.protocol.data.game.recipe.display.slot.EmptySlotDisplay;
|
||||
import org.geysermc.mcprotocollib.protocol.data.game.recipe.display.slot.SlotDisplay;
|
||||
|
||||
import java.util.*;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.EnumMap;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
@AllArgsConstructor
|
||||
public abstract class InventoryTranslator {
|
||||
@ -642,8 +666,8 @@ public abstract class InventoryTranslator {
|
||||
}
|
||||
int gridDimensions = gridSize == 4 ? 2 : 3;
|
||||
|
||||
Ingredient[] ingredients = new Ingredient[0];
|
||||
ItemStack output = null;
|
||||
List<SlotDisplay> ingredients = Collections.emptyList();
|
||||
SlotDisplay output = null;
|
||||
int recipeWidth = 0;
|
||||
int ingRemaining = 0;
|
||||
int ingredientIndex = -1;
|
||||
@ -697,7 +721,7 @@ public abstract class InventoryTranslator {
|
||||
ingredients = shapelessRecipe.ingredients();
|
||||
recipeWidth = gridDimensions;
|
||||
output = shapelessRecipe.result();
|
||||
if (ingredients.length > gridSize) {
|
||||
if (ingredients.size() > gridSize) {
|
||||
return rejectRequest(request);
|
||||
}
|
||||
}
|
||||
@ -728,8 +752,8 @@ public abstract class InventoryTranslator {
|
||||
craftState = CraftState.INGREDIENTS;
|
||||
|
||||
if (ingRemaining == 0) {
|
||||
while (++ingredientIndex < ingredients.length) {
|
||||
if (ingredients[ingredientIndex].getOptions().length != 0) {
|
||||
while (++ingredientIndex < ingredients.size()) {
|
||||
if (!(ingredients.get(ingredientIndex) instanceof EmptySlotDisplay)) { // TODO I guess can technically other options be empty?
|
||||
ingRemaining = timesCrafted;
|
||||
break;
|
||||
}
|
||||
|
@ -33,6 +33,11 @@ import org.geysermc.geyser.inventory.updater.UIInventoryUpdater;
|
||||
import org.geysermc.geyser.level.block.Blocks;
|
||||
|
||||
public class SmithingInventoryTranslator extends AbstractBlockInventoryTranslator {
|
||||
public static final int TEMPLATE = 0;
|
||||
public static final int INPUT = 1;
|
||||
public static final int MATERIAL = 2;
|
||||
public static final int OUTPUT = 3;
|
||||
|
||||
public SmithingInventoryTranslator() {
|
||||
super(4, Blocks.SMITHING_TABLE, ContainerType.SMITHING_TABLE, UIInventoryUpdater.INSTANCE);
|
||||
}
|
||||
@ -40,10 +45,10 @@ public class SmithingInventoryTranslator extends AbstractBlockInventoryTranslato
|
||||
@Override
|
||||
public int bedrockSlotToJava(ItemStackRequestSlotData slotInfoData) {
|
||||
return switch (slotInfoData.getContainer()) {
|
||||
case SMITHING_TABLE_TEMPLATE -> 0;
|
||||
case SMITHING_TABLE_INPUT -> 1;
|
||||
case SMITHING_TABLE_MATERIAL -> 2;
|
||||
case SMITHING_TABLE_RESULT, CREATED_OUTPUT -> 3;
|
||||
case SMITHING_TABLE_TEMPLATE -> TEMPLATE;
|
||||
case SMITHING_TABLE_INPUT -> INPUT;
|
||||
case SMITHING_TABLE_MATERIAL -> MATERIAL;
|
||||
case SMITHING_TABLE_RESULT, CREATED_OUTPUT -> OUTPUT;
|
||||
default -> super.bedrockSlotToJava(slotInfoData);
|
||||
};
|
||||
}
|
||||
@ -51,10 +56,10 @@ public class SmithingInventoryTranslator extends AbstractBlockInventoryTranslato
|
||||
@Override
|
||||
public BedrockContainerSlot javaSlotToBedrockContainer(int slot) {
|
||||
return switch (slot) {
|
||||
case 0 -> new BedrockContainerSlot(ContainerSlotType.SMITHING_TABLE_TEMPLATE, 53);
|
||||
case 1 -> new BedrockContainerSlot(ContainerSlotType.SMITHING_TABLE_INPUT, 51);
|
||||
case 2 -> new BedrockContainerSlot(ContainerSlotType.SMITHING_TABLE_MATERIAL, 52);
|
||||
case 3 -> new BedrockContainerSlot(ContainerSlotType.SMITHING_TABLE_RESULT, 50);
|
||||
case TEMPLATE -> new BedrockContainerSlot(ContainerSlotType.SMITHING_TABLE_TEMPLATE, 53);
|
||||
case INPUT -> new BedrockContainerSlot(ContainerSlotType.SMITHING_TABLE_INPUT, 51);
|
||||
case MATERIAL -> new BedrockContainerSlot(ContainerSlotType.SMITHING_TABLE_MATERIAL, 52);
|
||||
case OUTPUT -> new BedrockContainerSlot(ContainerSlotType.SMITHING_TABLE_RESULT, 50);
|
||||
default -> super.javaSlotToBedrockContainer(slot);
|
||||
};
|
||||
}
|
||||
@ -62,10 +67,10 @@ public class SmithingInventoryTranslator extends AbstractBlockInventoryTranslato
|
||||
@Override
|
||||
public int javaSlotToBedrock(int slot) {
|
||||
return switch (slot) {
|
||||
case 0 -> 53;
|
||||
case 1 -> 51;
|
||||
case 2 -> 52;
|
||||
case 3 -> 50;
|
||||
case TEMPLATE -> 53;
|
||||
case INPUT -> 51;
|
||||
case MATERIAL -> 52;
|
||||
case OUTPUT -> 50;
|
||||
default -> super.javaSlotToBedrock(slot);
|
||||
};
|
||||
}
|
||||
|
@ -108,7 +108,7 @@ public final class ItemTranslator {
|
||||
ItemMapping bedrockItem = session.getItemMappings().getMapping(data);
|
||||
Item javaItem = bedrockItem.getJavaItem();
|
||||
|
||||
GeyserItemStack itemStack = javaItem.translateToJava(data, bedrockItem, session.getItemMappings());
|
||||
GeyserItemStack itemStack = javaItem.translateToJava(session, data, bedrockItem, session.getItemMappings());
|
||||
|
||||
NbtMap nbt = data.getTag();
|
||||
if (nbt != null && !nbt.isEmpty()) {
|
||||
@ -198,7 +198,7 @@ public final class ItemTranslator {
|
||||
nbtMapBuilder.putIfAbsent("ench", NbtList.EMPTY);
|
||||
}
|
||||
|
||||
ItemData.Builder builder = javaItem.translateToBedrock(count, components, bedrockItem, session.getItemMappings());
|
||||
ItemData.Builder builder = javaItem.translateToBedrock(session, count, components, bedrockItem, session.getItemMappings());
|
||||
// Finalize the Bedrock NBT
|
||||
builder.tag(nbtBuilder.build());
|
||||
if (bedrockItem.isBlock()) {
|
||||
|
@ -25,13 +25,12 @@
|
||||
|
||||
package org.geysermc.geyser.translator.protocol.bedrock;
|
||||
|
||||
import org.geysermc.mcprotocollib.protocol.data.game.entity.player.Hand;
|
||||
import org.geysermc.mcprotocollib.protocol.packet.ingame.serverbound.level.ServerboundPaddleBoatPacket;
|
||||
import org.geysermc.mcprotocollib.protocol.packet.ingame.serverbound.player.ServerboundSwingPacket;
|
||||
import org.cloudburstmc.protocol.bedrock.packet.AnimatePacket;
|
||||
import org.geysermc.geyser.session.GeyserSession;
|
||||
import org.geysermc.geyser.translator.protocol.PacketTranslator;
|
||||
import org.geysermc.geyser.translator.protocol.Translator;
|
||||
import org.geysermc.mcprotocollib.protocol.data.game.entity.player.Hand;
|
||||
import org.geysermc.mcprotocollib.protocol.packet.ingame.serverbound.player.ServerboundSwingPacket;
|
||||
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
@ -45,45 +44,31 @@ public class BedrockAnimateTranslator extends PacketTranslator<AnimatePacket> {
|
||||
return;
|
||||
}
|
||||
|
||||
switch (packet.getAction()) {
|
||||
case SWING_ARM -> {
|
||||
session.armSwingPending();
|
||||
// Delay so entity damage can be processed first
|
||||
session.scheduleInEventLoop(() -> {
|
||||
if (session.getArmAnimationTicks() != 0) {
|
||||
// So, generally, a Java player can only do one *thing* at a time.
|
||||
// If a player right-clicks, for example, then there's probably only one action associated with
|
||||
// that right-click that will send a swing.
|
||||
// The only exception I can think of to this, *maybe*, is a player dropping items
|
||||
// Bedrock is a little funkier than this - it can send several arm animation packets in the
|
||||
// same tick, notably with high levels of haste applied.
|
||||
// Packet limiters do not like this and can crash the player.
|
||||
// If arm animation ticks is 0, then we just sent an arm swing packet this tick.
|
||||
// See https://github.com/GeyserMC/Geyser/issues/2875
|
||||
// This behavior was last touched on with ViaVersion 4.5.1 (with its packet limiter), Java 1.16.5,
|
||||
// and Bedrock 1.19.51.
|
||||
// Note for the future: we should probably largely ignore this packet and instead replicate
|
||||
// all actions on our end, and send swings where needed.
|
||||
session.sendDownstreamGamePacket(new ServerboundSwingPacket(Hand.MAIN_HAND));
|
||||
session.activateArmAnimationTicking();
|
||||
}
|
||||
},
|
||||
25,
|
||||
TimeUnit.MILLISECONDS
|
||||
);
|
||||
}
|
||||
// These two might need to be flipped, but my recommendation is getting moving working first
|
||||
case ROW_LEFT -> {
|
||||
// Packet value is a float of how long one has been rowing, so we convert that into a boolean
|
||||
session.setSteeringLeft(packet.getRowingTime() > 0.0);
|
||||
ServerboundPaddleBoatPacket steerLeftPacket = new ServerboundPaddleBoatPacket(session.isSteeringLeft(), session.isSteeringRight());
|
||||
session.sendDownstreamGamePacket(steerLeftPacket);
|
||||
}
|
||||
case ROW_RIGHT -> {
|
||||
session.setSteeringRight(packet.getRowingTime() > 0.0);
|
||||
ServerboundPaddleBoatPacket steerRightPacket = new ServerboundPaddleBoatPacket(session.isSteeringLeft(), session.isSteeringRight());
|
||||
session.sendDownstreamGamePacket(steerRightPacket);
|
||||
}
|
||||
if (packet.getAction() == AnimatePacket.Action.SWING_ARM) {
|
||||
session.armSwingPending();
|
||||
// Delay so entity damage can be processed first
|
||||
session.scheduleInEventLoop(() -> {
|
||||
if (session.getArmAnimationTicks() != 0) {
|
||||
// So, generally, a Java player can only do one *thing* at a time.
|
||||
// If a player right-clicks, for example, then there's probably only one action associated with
|
||||
// that right-click that will send a swing.
|
||||
// The only exception I can think of to this, *maybe*, is a player dropping items
|
||||
// Bedrock is a little funkier than this - it can send several arm animation packets in the
|
||||
// same tick, notably with high levels of haste applied.
|
||||
// Packet limiters do not like this and can crash the player.
|
||||
// If arm animation ticks is 0, then we just sent an arm swing packet this tick.
|
||||
// See https://github.com/GeyserMC/Geyser/issues/2875
|
||||
// This behavior was last touched on with ViaVersion 4.5.1 (with its packet limiter), Java 1.16.5,
|
||||
// and Bedrock 1.19.51.
|
||||
// Note for the future: we should probably largely ignore this packet and instead replicate
|
||||
// all actions on our end, and send swings where needed.
|
||||
session.sendDownstreamGamePacket(new ServerboundSwingPacket(Hand.MAIN_HAND));
|
||||
session.activateArmAnimationTicking();
|
||||
}
|
||||
},
|
||||
25,
|
||||
TimeUnit.MILLISECONDS
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -51,29 +51,14 @@ public class BedrockEntityPickRequestTranslator extends PacketTranslator<EntityP
|
||||
Entity entity = session.getEntityCache().getEntityByGeyserId(packet.getRuntimeEntityId());
|
||||
if (entity == null) return;
|
||||
|
||||
if (entity instanceof BoatEntity boat) {
|
||||
InventoryUtils.findOrCreateItem(session, boat.getPickItem());
|
||||
return;
|
||||
}
|
||||
|
||||
// Get the corresponding item
|
||||
String itemName;
|
||||
switch (entity.getDefinition().entityType()) {
|
||||
case BOAT, CHEST_BOAT -> {
|
||||
// Include type of boat in the name
|
||||
int variant = ((BoatEntity) entity).getVariant();
|
||||
String typeOfBoat = switch (variant) {
|
||||
case 1 -> "spruce";
|
||||
case 2 -> "birch";
|
||||
case 3 -> "jungle";
|
||||
case 4 -> "acacia";
|
||||
case 5 -> "cherry";
|
||||
case 6 -> "dark_oak";
|
||||
case 7 -> "mangrove";
|
||||
case 8 -> "bamboo";
|
||||
default -> "oak";
|
||||
};
|
||||
itemName = typeOfBoat + "_" + entity.getDefinition().entityType().name().toLowerCase(Locale.ROOT);
|
||||
// Bamboo boat is a raft
|
||||
if (variant == 8) {
|
||||
itemName = itemName.replace("boat", "raft");
|
||||
}
|
||||
}
|
||||
case LEASH_KNOT -> itemName = "lead";
|
||||
case CHEST_MINECART, COMMAND_BLOCK_MINECART, FURNACE_MINECART, HOPPER_MINECART, TNT_MINECART ->
|
||||
// The Bedrock identifier matches the item name which moves MINECART to the end of the name
|
||||
|
@ -30,7 +30,6 @@ import it.unimi.dsi.fastutil.ints.Int2ObjectMaps;
|
||||
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;
|
||||
@ -42,8 +41,8 @@ import org.cloudburstmc.protocol.bedrock.data.inventory.transaction.InventoryTra
|
||||
import org.cloudburstmc.protocol.bedrock.data.inventory.transaction.LegacySetItemSlotData;
|
||||
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.PlaySoundPacket;
|
||||
import org.cloudburstmc.protocol.bedrock.packet.UpdateBlockPacket;
|
||||
import org.geysermc.geyser.entity.EntityDefinitions;
|
||||
import org.geysermc.geyser.entity.type.Entity;
|
||||
@ -53,6 +52,7 @@ import org.geysermc.geyser.inventory.GeyserItemStack;
|
||||
import org.geysermc.geyser.inventory.Inventory;
|
||||
import org.geysermc.geyser.inventory.PlayerInventory;
|
||||
import org.geysermc.geyser.inventory.click.Click;
|
||||
import org.geysermc.geyser.inventory.item.GeyserInstrument;
|
||||
import org.geysermc.geyser.item.Items;
|
||||
import org.geysermc.geyser.item.type.BlockItem;
|
||||
import org.geysermc.geyser.item.type.BoatItem;
|
||||
@ -77,6 +77,7 @@ 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.geyser.util.SoundUtils;
|
||||
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;
|
||||
@ -187,7 +188,7 @@ public class BedrockInventoryTransactionTranslator extends PacketTranslator<Inve
|
||||
default -> false;
|
||||
};
|
||||
if (isGodBridging) {
|
||||
restoreCorrectBlock(session, blockPos, packet);
|
||||
restoreCorrectBlock(session, blockPos);
|
||||
return;
|
||||
}
|
||||
}
|
||||
@ -207,7 +208,7 @@ public class BedrockInventoryTransactionTranslator extends PacketTranslator<Inve
|
||||
int belowBlock = session.getGeyser().getWorldManager().getBlockAt(session, belowBlockPos);
|
||||
BlockDefinition extendedCollisionDefinition = session.getBlockMappings().getExtendedCollisionBoxes().get(belowBlock);
|
||||
if (extendedCollisionDefinition != null && (System.currentTimeMillis() - session.getLastInteractionTime()) < 200) {
|
||||
restoreCorrectBlock(session, blockPos, packet);
|
||||
restoreCorrectBlock(session, blockPos);
|
||||
return;
|
||||
}
|
||||
}
|
||||
@ -227,7 +228,7 @@ public class BedrockInventoryTransactionTranslator extends PacketTranslator<Inve
|
||||
}
|
||||
|
||||
if (isIncorrectHeldItem(session, packet)) {
|
||||
restoreCorrectBlock(session, blockPos, packet);
|
||||
restoreCorrectBlock(session, blockPos);
|
||||
return;
|
||||
}
|
||||
|
||||
@ -247,7 +248,7 @@ public class BedrockInventoryTransactionTranslator extends PacketTranslator<Inve
|
||||
*/
|
||||
// Blocks cannot be placed or destroyed outside of the world border
|
||||
if (!session.getWorldBorder().isInsideBorderBoundaries()) {
|
||||
restoreCorrectBlock(session, blockPos, packet);
|
||||
restoreCorrectBlock(session, blockPos);
|
||||
return;
|
||||
}
|
||||
|
||||
@ -256,7 +257,7 @@ public class BedrockInventoryTransactionTranslator extends PacketTranslator<Inve
|
||||
playerPosition = playerPosition.down(EntityDefinitions.PLAYER.offset() - session.getEyeHeight());
|
||||
|
||||
if (!canInteractWithBlock(session, playerPosition, packetBlockPosition)) {
|
||||
restoreCorrectBlock(session, blockPos, packet);
|
||||
restoreCorrectBlock(session, blockPos);
|
||||
return;
|
||||
}
|
||||
|
||||
@ -270,7 +271,7 @@ public class BedrockInventoryTransactionTranslator extends PacketTranslator<Inve
|
||||
double clickDistanceY = clickPositionFullY - blockCenter.getY();
|
||||
double clickDistanceZ = clickPositionFullZ - blockCenter.getZ();
|
||||
if (!(Math.abs(clickDistanceX) < 1.0000001D && Math.abs(clickDistanceY) < 1.0000001D && Math.abs(clickDistanceZ) < 1.0000001D)) {
|
||||
restoreCorrectBlock(session, blockPos, packet);
|
||||
restoreCorrectBlock(session, blockPos);
|
||||
return;
|
||||
}
|
||||
|
||||
@ -296,6 +297,7 @@ public class BedrockInventoryTransactionTranslator extends PacketTranslator<Inve
|
||||
Hand.MAIN_HAND,
|
||||
packet.getClickPosition().getX(), packet.getClickPosition().getY(), packet.getClickPosition().getZ(),
|
||||
false,
|
||||
false,
|
||||
sequence);
|
||||
session.sendDownstreamGamePacket(blockPacket);
|
||||
|
||||
@ -380,18 +382,28 @@ public class BedrockInventoryTransactionTranslator extends PacketTranslator<Inve
|
||||
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()
|
||||
if (!session.getWorldCache().hasCooldown(session.getPlayerInventory().getItemInHand())) {
|
||||
Holder<Instrument> holder = 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);
|
||||
if (holder != null) {
|
||||
GeyserInstrument instrument = GeyserInstrument.fromHolder(session, holder);
|
||||
if (instrument.bedrockInstrument() != null) {
|
||||
// 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.bedrockInstrument().ordinal()));
|
||||
soundPacket.setPosition(session.getPlayerEntity().getPosition());
|
||||
soundPacket.setIdentifier("minecraft:player");
|
||||
soundPacket.setExtraData(-1);
|
||||
session.sendUpstreamPacket(soundPacket);
|
||||
} else {
|
||||
PlaySoundPacket playSoundPacket = new PlaySoundPacket();
|
||||
playSoundPacket.setPosition(session.getPlayerEntity().position());
|
||||
playSoundPacket.setSound(SoundUtils.translatePlaySound(instrument.soundEvent()));
|
||||
playSoundPacket.setPitch(1.0F);
|
||||
playSoundPacket.setVolume(instrument.range() / 16.0F);
|
||||
session.sendUpstreamPacket(playSoundPacket);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -423,53 +435,6 @@ public class BedrockInventoryTransactionTranslator extends PacketTranslator<Inve
|
||||
}
|
||||
}
|
||||
}
|
||||
case 2 -> {
|
||||
int blockState = session.getGameMode() == GameMode.CREATIVE ?
|
||||
session.getGeyser().getWorldManager().getBlockAt(session, packet.getBlockPosition()) : session.getBreakingBlock();
|
||||
|
||||
session.setLastBlockPlaced(null);
|
||||
session.setLastBlockPlacePosition(null);
|
||||
|
||||
// Same deal with vanilla block placing as above.
|
||||
if (!session.getWorldBorder().isInsideBorderBoundaries()) {
|
||||
restoreCorrectBlock(session, packet.getBlockPosition(), packet);
|
||||
return;
|
||||
}
|
||||
|
||||
Vector3f playerPosition = session.getPlayerEntity().getPosition();
|
||||
playerPosition = playerPosition.down(EntityDefinitions.PLAYER.offset() - session.getEyeHeight());
|
||||
|
||||
if (!canInteractWithBlock(session, playerPosition, packet.getBlockPosition())) {
|
||||
restoreCorrectBlock(session, packet.getBlockPosition(), packet);
|
||||
return;
|
||||
}
|
||||
|
||||
int sequence = session.getWorldCache().nextPredictionSequence();
|
||||
session.getWorldCache().markPositionInSequence(packet.getBlockPosition());
|
||||
// -1 means we don't know what block they're breaking
|
||||
if (blockState == -1) {
|
||||
blockState = Block.JAVA_AIR_ID;
|
||||
}
|
||||
|
||||
LevelEventPacket blockBreakPacket = new LevelEventPacket();
|
||||
blockBreakPacket.setType(LevelEvent.PARTICLE_DESTROY_BLOCK);
|
||||
blockBreakPacket.setPosition(packet.getBlockPosition().toFloat());
|
||||
blockBreakPacket.setData(session.getBlockMappings().getBedrockBlockId(blockState));
|
||||
session.sendUpstreamPacket(blockBreakPacket);
|
||||
session.setBreakingBlock(-1);
|
||||
|
||||
Entity itemFrameEntity = ItemFrameEntity.getItemFrameEntity(session, packet.getBlockPosition());
|
||||
if (itemFrameEntity != null) {
|
||||
ServerboundInteractPacket attackPacket = new ServerboundInteractPacket(itemFrameEntity.getEntityId(),
|
||||
InteractAction.ATTACK, session.isSneaking());
|
||||
session.sendDownstreamGamePacket(attackPacket);
|
||||
break;
|
||||
}
|
||||
|
||||
PlayerAction action = session.getGameMode() == GameMode.CREATIVE ? PlayerAction.START_DIGGING : PlayerAction.FINISH_DIGGING;
|
||||
ServerboundPlayerActionPacket breakPacket = new ServerboundPlayerActionPacket(action, packet.getBlockPosition(), Direction.VALUES[packet.getBlockFace()], sequence);
|
||||
session.sendDownstreamGamePacket(breakPacket);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case ITEM_RELEASE:
|
||||
@ -549,7 +514,7 @@ public class BedrockInventoryTransactionTranslator extends PacketTranslator<Inve
|
||||
}
|
||||
}
|
||||
|
||||
private boolean canInteractWithBlock(GeyserSession session, Vector3f playerPosition, Vector3i packetBlockPosition) {
|
||||
public static boolean canInteractWithBlock(GeyserSession session, Vector3f playerPosition, Vector3i packetBlockPosition) {
|
||||
// ViaVersion sends this 1.20.5+ attribute also, so older servers will have correct range checks.
|
||||
double blockInteractionRange = session.getPlayerEntity().getBlockInteractionRange();
|
||||
|
||||
@ -577,7 +542,7 @@ public class BedrockInventoryTransactionTranslator extends PacketTranslator<Inve
|
||||
* @param session the session of the Bedrock client
|
||||
* @param blockPos the block position to restore
|
||||
*/
|
||||
private void restoreCorrectBlock(GeyserSession session, Vector3i blockPos, InventoryTransactionPacket packet) {
|
||||
public static void restoreCorrectBlock(GeyserSession session, Vector3i blockPos) {
|
||||
BlockState javaBlockState = session.getGeyser().getWorldManager().blockAt(session, blockPos);
|
||||
BlockDefinition bedrockBlock = session.getBlockMappings().getBedrockBlock(javaBlockState);
|
||||
|
||||
@ -604,7 +569,7 @@ public class BedrockInventoryTransactionTranslator extends PacketTranslator<Inve
|
||||
session.sendUpstreamPacket(updateWaterPacket);
|
||||
|
||||
// Reset the item in hand to prevent "missing" blocks
|
||||
InventoryTranslator.PLAYER_INVENTORY_TRANSLATOR.updateSlot(session, session.getPlayerInventory(), session.getPlayerInventory().getOffsetForHotbar(packet.getHotbarSlot()));
|
||||
InventoryTranslator.PLAYER_INVENTORY_TRANSLATOR.updateSlot(session, session.getPlayerInventory(), session.getPlayerInventory().getHeldItemSlot()); // TODO test
|
||||
}
|
||||
|
||||
private boolean isIncorrectHeldItem(GeyserSession session, InventoryTransactionPacket packet) {
|
||||
@ -698,9 +663,11 @@ public class BedrockInventoryTransactionTranslator extends PacketTranslator<Inve
|
||||
float pitch = (float) -Math.toDegrees(Math.atan2(yDiff, xzHypot));
|
||||
|
||||
SessionPlayerEntity entity = session.getPlayerEntity();
|
||||
ServerboundMovePlayerPosRotPacket returnPacket = new ServerboundMovePlayerPosRotPacket(entity.isOnGround(), playerPosition.getX(), playerPosition.getY(), playerPosition.getZ(), entity.getYaw(), entity.getPitch());
|
||||
ServerboundMovePlayerPosRotPacket returnPacket = new ServerboundMovePlayerPosRotPacket(entity.isOnGround(), session.getInputCache().lastHorizontalCollision(),
|
||||
playerPosition.getX(), playerPosition.getY(), playerPosition.getZ(), entity.getYaw(), entity.getPitch());
|
||||
// This matches Java edition behavior
|
||||
ServerboundMovePlayerPosRotPacket movementPacket = new ServerboundMovePlayerPosRotPacket(entity.isOnGround(), playerPosition.getX(), playerPosition.getY(), playerPosition.getZ(), yaw, pitch);
|
||||
ServerboundMovePlayerPosRotPacket movementPacket = new ServerboundMovePlayerPosRotPacket(entity.isOnGround(), session.getInputCache().lastHorizontalCollision(),
|
||||
playerPosition.getX(), playerPosition.getY(), playerPosition.getZ(), yaw, pitch);
|
||||
session.sendDownstreamGamePacket(movementPacket);
|
||||
|
||||
if (session.getLookBackScheduledFuture() != null) {
|
||||
|
@ -1,77 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2019-2022 GeyserMC. http://geysermc.org
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*
|
||||
* @author GeyserMC
|
||||
* @link https://github.com/GeyserMC/Geyser
|
||||
*/
|
||||
|
||||
package org.geysermc.geyser.translator.protocol.bedrock;
|
||||
|
||||
import org.cloudburstmc.math.vector.Vector3f;
|
||||
import org.cloudburstmc.protocol.bedrock.packet.MoveEntityAbsolutePacket;
|
||||
import org.geysermc.geyser.entity.EntityDefinitions;
|
||||
import org.geysermc.geyser.entity.type.BoatEntity;
|
||||
import org.geysermc.geyser.entity.type.Entity;
|
||||
import org.geysermc.geyser.session.GeyserSession;
|
||||
import org.geysermc.geyser.translator.protocol.PacketTranslator;
|
||||
import org.geysermc.geyser.translator.protocol.Translator;
|
||||
import org.geysermc.mcprotocollib.protocol.packet.ingame.serverbound.level.ServerboundMoveVehiclePacket;
|
||||
|
||||
/**
|
||||
* Sent by the client when moving a horse or boat.
|
||||
*/
|
||||
@Translator(packet = MoveEntityAbsolutePacket.class)
|
||||
public class BedrockMoveEntityAbsoluteTranslator extends PacketTranslator<MoveEntityAbsolutePacket> {
|
||||
|
||||
@Override
|
||||
public void translate(GeyserSession session, MoveEntityAbsolutePacket packet) {
|
||||
session.setLastVehicleMoveTimestamp(System.currentTimeMillis());
|
||||
|
||||
Entity ridingEntity = session.getPlayerEntity().getVehicle();
|
||||
if (ridingEntity != null && session.getWorldBorder().isPassingIntoBorderBoundaries(packet.getPosition(), false)) {
|
||||
Vector3f position = Vector3f.from(ridingEntity.getPosition().getX(), packet.getPosition().getY(),
|
||||
ridingEntity.getPosition().getZ());
|
||||
if (ridingEntity instanceof BoatEntity) {
|
||||
// Undo the changes usually applied to the boat
|
||||
ridingEntity.as(BoatEntity.class)
|
||||
.moveAbsoluteWithoutAdjustments(position, ridingEntity.getYaw(),
|
||||
ridingEntity.isOnGround(), true);
|
||||
} else {
|
||||
// This doesn't work if teleported is false
|
||||
ridingEntity.moveAbsolute(position,
|
||||
ridingEntity.getYaw(), ridingEntity.getPitch(), ridingEntity.getHeadYaw(),
|
||||
ridingEntity.isOnGround(), true);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
float y = packet.getPosition().getY();
|
||||
if (ridingEntity instanceof BoatEntity && !ridingEntity.isOnGround()) {
|
||||
// Remove the offset to prevents boats from looking like they're floating in water
|
||||
y -= EntityDefinitions.BOAT.offset();
|
||||
}
|
||||
ServerboundMoveVehiclePacket ServerboundMoveVehiclePacket = new ServerboundMoveVehiclePacket(
|
||||
packet.getPosition().getX(), y, packet.getPosition().getZ(),
|
||||
packet.getRotation().getY() - 90, packet.getRotation().getX()
|
||||
);
|
||||
session.sendDownstreamGamePacket(ServerboundMoveVehiclePacket);
|
||||
}
|
||||
}
|
@ -1,92 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2019-2022 GeyserMC. http://geysermc.org
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*
|
||||
* @author GeyserMC
|
||||
* @link https://github.com/GeyserMC/Geyser
|
||||
*/
|
||||
|
||||
package org.geysermc.geyser.translator.protocol.bedrock;
|
||||
|
||||
import org.geysermc.mcprotocollib.protocol.packet.ingame.serverbound.level.ServerboundMoveVehiclePacket;
|
||||
import org.geysermc.mcprotocollib.protocol.packet.ingame.serverbound.level.ServerboundPlayerInputPacket;
|
||||
import org.cloudburstmc.math.vector.Vector3f;
|
||||
import org.cloudburstmc.protocol.bedrock.packet.PlayerInputPacket;
|
||||
import org.geysermc.geyser.entity.EntityDefinitions;
|
||||
import org.geysermc.geyser.entity.type.BoatEntity;
|
||||
import org.geysermc.geyser.entity.type.Entity;
|
||||
import org.geysermc.geyser.entity.type.living.animal.horse.AbstractHorseEntity;
|
||||
import org.geysermc.geyser.entity.type.living.animal.horse.LlamaEntity;
|
||||
import org.geysermc.geyser.session.GeyserSession;
|
||||
import org.geysermc.geyser.translator.protocol.PacketTranslator;
|
||||
import org.geysermc.geyser.translator.protocol.Translator;
|
||||
|
||||
/**
|
||||
* Sent by the client for minecarts and boats.
|
||||
*/
|
||||
@Translator(packet = PlayerInputPacket.class)
|
||||
public class BedrockPlayerInputTranslator extends PacketTranslator<PlayerInputPacket> {
|
||||
|
||||
@Override
|
||||
public void translate(GeyserSession session, PlayerInputPacket packet) {
|
||||
ServerboundPlayerInputPacket playerInputPacket = new ServerboundPlayerInputPacket(
|
||||
packet.getInputMotion().getX(), packet.getInputMotion().getY(), packet.isJumping(), packet.isSneaking()
|
||||
);
|
||||
|
||||
session.sendDownstreamGamePacket(playerInputPacket);
|
||||
|
||||
session.getPlayerEntity().setVehicleInput(packet.getInputMotion());
|
||||
|
||||
// Bedrock only sends movement vehicle packets while moving
|
||||
// This allows horses to take damage while standing on magma
|
||||
Entity vehicle = session.getPlayerEntity().getVehicle();
|
||||
boolean sendMovement = false;
|
||||
if (vehicle instanceof AbstractHorseEntity && !(vehicle instanceof LlamaEntity)) {
|
||||
sendMovement = vehicle.isOnGround();
|
||||
} else if (vehicle instanceof BoatEntity) {
|
||||
if (vehicle.getPassengers().size() == 1) {
|
||||
// The player is the only rider
|
||||
sendMovement = true;
|
||||
} else {
|
||||
// Check if the player is the front rider
|
||||
if (session.getPlayerEntity().isRidingInFront()) {
|
||||
sendMovement = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (sendMovement) {
|
||||
long timeSinceVehicleMove = System.currentTimeMillis() - session.getLastVehicleMoveTimestamp();
|
||||
if (timeSinceVehicleMove >= 100) {
|
||||
Vector3f vehiclePosition = vehicle.getPosition();
|
||||
|
||||
if (vehicle instanceof BoatEntity && !vehicle.isOnGround()) {
|
||||
// Remove some Y position to prevents boats flying up
|
||||
vehiclePosition = vehiclePosition.down(EntityDefinitions.BOAT.offset());
|
||||
}
|
||||
|
||||
ServerboundMoveVehiclePacket moveVehiclePacket = new ServerboundMoveVehiclePacket(
|
||||
vehiclePosition.getX(), vehiclePosition.getY(), vehiclePosition.getZ(),
|
||||
vehicle.getYaw() - 90, vehicle.getPitch()
|
||||
);
|
||||
session.sendDownstreamGamePacket(moveVehiclePacket);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -1,387 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2019-2022 GeyserMC. http://geysermc.org
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*
|
||||
* @author GeyserMC
|
||||
* @link https://github.com/GeyserMC/Geyser
|
||||
*/
|
||||
|
||||
package org.geysermc.geyser.translator.protocol.bedrock.entity.player;
|
||||
|
||||
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.PlayerActionType;
|
||||
import org.cloudburstmc.protocol.bedrock.data.definitions.ItemDefinition;
|
||||
import org.cloudburstmc.protocol.bedrock.data.entity.EntityEventType;
|
||||
import org.cloudburstmc.protocol.bedrock.data.entity.EntityFlag;
|
||||
import org.cloudburstmc.protocol.bedrock.packet.AnimatePacket;
|
||||
import org.cloudburstmc.protocol.bedrock.packet.EntityEventPacket;
|
||||
import org.cloudburstmc.protocol.bedrock.packet.LevelEventPacket;
|
||||
import org.cloudburstmc.protocol.bedrock.packet.PlayStatusPacket;
|
||||
import org.cloudburstmc.protocol.bedrock.packet.PlayerActionPacket;
|
||||
import org.cloudburstmc.protocol.bedrock.packet.UpdateAttributesPacket;
|
||||
import org.geysermc.geyser.api.block.custom.CustomBlockState;
|
||||
import org.geysermc.geyser.entity.type.Entity;
|
||||
import org.geysermc.geyser.entity.type.ItemFrameEntity;
|
||||
import org.geysermc.geyser.entity.type.player.SessionPlayerEntity;
|
||||
import org.geysermc.geyser.inventory.GeyserItemStack;
|
||||
import org.geysermc.geyser.level.block.Blocks;
|
||||
import org.geysermc.geyser.level.block.property.Properties;
|
||||
import org.geysermc.geyser.level.block.type.Block;
|
||||
import org.geysermc.geyser.level.block.type.BlockState;
|
||||
import org.geysermc.geyser.registry.BlockRegistries;
|
||||
import org.geysermc.geyser.registry.type.ItemMapping;
|
||||
import org.geysermc.geyser.session.GeyserSession;
|
||||
import org.geysermc.geyser.session.cache.SkullCache;
|
||||
import org.geysermc.geyser.translator.item.CustomItemTranslator;
|
||||
import org.geysermc.geyser.translator.protocol.PacketTranslator;
|
||||
import org.geysermc.geyser.translator.protocol.Translator;
|
||||
import org.geysermc.geyser.util.BlockUtils;
|
||||
import org.geysermc.geyser.util.CooldownUtils;
|
||||
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.entity.player.PlayerState;
|
||||
import org.geysermc.mcprotocollib.protocol.packet.ingame.serverbound.player.ServerboundInteractPacket;
|
||||
import org.geysermc.mcprotocollib.protocol.packet.ingame.serverbound.player.ServerboundPlayerAbilitiesPacket;
|
||||
import org.geysermc.mcprotocollib.protocol.packet.ingame.serverbound.player.ServerboundPlayerActionPacket;
|
||||
import org.geysermc.mcprotocollib.protocol.packet.ingame.serverbound.player.ServerboundPlayerCommandPacket;
|
||||
import org.geysermc.mcprotocollib.protocol.packet.ingame.serverbound.player.ServerboundSwingPacket;
|
||||
import org.geysermc.mcprotocollib.protocol.packet.ingame.serverbound.player.ServerboundUseItemOnPacket;
|
||||
|
||||
@Translator(packet = PlayerActionPacket.class)
|
||||
public class BedrockActionTranslator extends PacketTranslator<PlayerActionPacket> {
|
||||
|
||||
@Override
|
||||
public void translate(GeyserSession session, PlayerActionPacket packet) {
|
||||
SessionPlayerEntity entity = session.getPlayerEntity();
|
||||
|
||||
// Send book update before any player action
|
||||
if (packet.getAction() != PlayerActionType.RESPAWN) {
|
||||
session.getBookEditCache().checkForSend();
|
||||
}
|
||||
|
||||
Vector3i vector = packet.getBlockPosition();
|
||||
|
||||
switch (packet.getAction()) {
|
||||
case RESPAWN -> {
|
||||
// Respawn process is finished and the server and client are both OK with respawning.
|
||||
EntityEventPacket eventPacket = new EntityEventPacket();
|
||||
eventPacket.setRuntimeEntityId(entity.getGeyserId());
|
||||
eventPacket.setType(EntityEventType.RESPAWN);
|
||||
eventPacket.setData(0);
|
||||
session.sendUpstreamPacket(eventPacket);
|
||||
// Resend attributes or else in rare cases the user can think they're not dead when they are, upon joining the server
|
||||
UpdateAttributesPacket attributesPacket = new UpdateAttributesPacket();
|
||||
attributesPacket.setRuntimeEntityId(entity.getGeyserId());
|
||||
attributesPacket.getAttributes().addAll(entity.getAttributes().values());
|
||||
session.sendUpstreamPacket(attributesPacket);
|
||||
|
||||
// Bounding box must be sent after a player dies and respawns since 1.19.40
|
||||
entity.updateBoundingBox();
|
||||
|
||||
// Needed here since 1.19.81 for dimension switching
|
||||
session.getEntityCache().updateBossBars();
|
||||
}
|
||||
case START_SWIMMING -> {
|
||||
if (!entity.getFlag(EntityFlag.SWIMMING)) {
|
||||
ServerboundPlayerCommandPacket startSwimPacket = new ServerboundPlayerCommandPacket(entity.getEntityId(), PlayerState.START_SPRINTING);
|
||||
session.sendDownstreamGamePacket(startSwimPacket);
|
||||
|
||||
session.setSwimming(true);
|
||||
}
|
||||
}
|
||||
case STOP_SWIMMING -> {
|
||||
// Prevent packet spam when Bedrock players are crawling near the edge of a block
|
||||
if (!session.getCollisionManager().mustPlayerCrawlHere()) {
|
||||
ServerboundPlayerCommandPacket stopSwimPacket = new ServerboundPlayerCommandPacket(entity.getEntityId(), PlayerState.STOP_SPRINTING);
|
||||
session.sendDownstreamGamePacket(stopSwimPacket);
|
||||
|
||||
session.setSwimming(false);
|
||||
}
|
||||
}
|
||||
case START_GLIDE -> {
|
||||
// Otherwise gliding will not work in creative
|
||||
ServerboundPlayerAbilitiesPacket playerAbilitiesPacket = new ServerboundPlayerAbilitiesPacket(false);
|
||||
session.sendDownstreamGamePacket(playerAbilitiesPacket);
|
||||
sendPlayerGlideToggle(session, entity);
|
||||
}
|
||||
case STOP_GLIDE -> sendPlayerGlideToggle(session, entity);
|
||||
case START_SNEAK -> {
|
||||
ServerboundPlayerCommandPacket startSneakPacket = new ServerboundPlayerCommandPacket(entity.getEntityId(), PlayerState.START_SNEAKING);
|
||||
session.sendDownstreamGamePacket(startSneakPacket);
|
||||
|
||||
session.startSneaking();
|
||||
}
|
||||
case STOP_SNEAK -> {
|
||||
ServerboundPlayerCommandPacket stopSneakPacket = new ServerboundPlayerCommandPacket(entity.getEntityId(), PlayerState.STOP_SNEAKING);
|
||||
session.sendDownstreamGamePacket(stopSneakPacket);
|
||||
|
||||
session.stopSneaking();
|
||||
}
|
||||
case START_SPRINT -> {
|
||||
if (!entity.getFlag(EntityFlag.SWIMMING)) {
|
||||
ServerboundPlayerCommandPacket startSprintPacket = new ServerboundPlayerCommandPacket(entity.getEntityId(), PlayerState.START_SPRINTING);
|
||||
session.sendDownstreamGamePacket(startSprintPacket);
|
||||
session.setSprinting(true);
|
||||
}
|
||||
}
|
||||
case STOP_SPRINT -> {
|
||||
if (!entity.getFlag(EntityFlag.SWIMMING)) {
|
||||
ServerboundPlayerCommandPacket stopSprintPacket = new ServerboundPlayerCommandPacket(entity.getEntityId(), PlayerState.STOP_SPRINTING);
|
||||
session.sendDownstreamGamePacket(stopSprintPacket);
|
||||
}
|
||||
session.setSprinting(false);
|
||||
}
|
||||
case DROP_ITEM -> {
|
||||
ServerboundPlayerActionPacket dropItemPacket = new ServerboundPlayerActionPacket(PlayerAction.DROP_ITEM,
|
||||
vector, Direction.VALUES[packet.getFace()], 0);
|
||||
session.sendDownstreamGamePacket(dropItemPacket);
|
||||
}
|
||||
case STOP_SLEEP -> {
|
||||
ServerboundPlayerCommandPacket stopSleepingPacket = new ServerboundPlayerCommandPacket(entity.getEntityId(), PlayerState.LEAVE_BED);
|
||||
session.sendDownstreamGamePacket(stopSleepingPacket);
|
||||
}
|
||||
case START_BREAK -> {
|
||||
// Ignore START_BREAK when the player is CREATIVE to avoid Spigot receiving 2 packets it interpets as block breaking. https://github.com/GeyserMC/Geyser/issues/4021
|
||||
if (session.getGameMode() == GameMode.CREATIVE) {
|
||||
break;
|
||||
}
|
||||
|
||||
// Start the block breaking animation
|
||||
int blockState = session.getGeyser().getWorldManager().getBlockAt(session, vector);
|
||||
LevelEventPacket startBreak = new LevelEventPacket();
|
||||
startBreak.setType(LevelEvent.BLOCK_START_BREAK);
|
||||
startBreak.setPosition(vector.toFloat());
|
||||
double breakTime = BlockUtils.getSessionBreakTime(session, BlockState.of(blockState).block()) * 20;
|
||||
|
||||
// If the block is custom or the breaking item is custom, we must keep track of break time ourselves
|
||||
GeyserItemStack item = session.getPlayerInventory().getItemInHand();
|
||||
ItemMapping mapping = item.getMapping(session);
|
||||
ItemDefinition customItem = mapping.isTool() ? CustomItemTranslator.getCustomItem(item.getComponents(), mapping) : null;
|
||||
CustomBlockState blockStateOverride = BlockRegistries.CUSTOM_BLOCK_STATE_OVERRIDES.get(blockState);
|
||||
SkullCache.Skull skull = session.getSkullCache().getSkulls().get(vector);
|
||||
|
||||
session.setBlockBreakStartTime(0);
|
||||
if (blockStateOverride != null || customItem != null || (skull != null && skull.getBlockDefinition() != null)) {
|
||||
session.setBlockBreakStartTime(System.currentTimeMillis());
|
||||
}
|
||||
startBreak.setData((int) (65535 / breakTime));
|
||||
session.setBreakingBlock(blockState);
|
||||
session.sendUpstreamPacket(startBreak);
|
||||
|
||||
// Account for fire - the client likes to hit the block behind.
|
||||
Vector3i fireBlockPos = BlockUtils.getBlockPosition(vector, packet.getFace());
|
||||
Block block = session.getGeyser().getWorldManager().blockAt(session, fireBlockPos).block();
|
||||
Direction direction = Direction.VALUES[packet.getFace()];
|
||||
if (block == Blocks.FIRE || block == Blocks.SOUL_FIRE) {
|
||||
ServerboundPlayerActionPacket startBreakingPacket = new ServerboundPlayerActionPacket(PlayerAction.START_DIGGING, fireBlockPos,
|
||||
direction, session.getWorldCache().nextPredictionSequence());
|
||||
session.sendDownstreamGamePacket(startBreakingPacket);
|
||||
}
|
||||
|
||||
ServerboundPlayerActionPacket startBreakingPacket = new ServerboundPlayerActionPacket(PlayerAction.START_DIGGING,
|
||||
vector, direction, session.getWorldCache().nextPredictionSequence());
|
||||
session.sendDownstreamGamePacket(startBreakingPacket);
|
||||
|
||||
spawnBlockBreakParticles(session, direction, vector, BlockState.of(blockState));
|
||||
}
|
||||
case CONTINUE_BREAK -> {
|
||||
if (session.getGameMode() == GameMode.CREATIVE) {
|
||||
break;
|
||||
}
|
||||
int breakingBlock = session.getBreakingBlock();
|
||||
if (breakingBlock == -1) {
|
||||
breakingBlock = Block.JAVA_AIR_ID;
|
||||
}
|
||||
|
||||
Vector3f vectorFloat = vector.toFloat();
|
||||
|
||||
BlockState breakingBlockState = BlockState.of(breakingBlock);
|
||||
Direction direction = Direction.VALUES[packet.getFace()];
|
||||
spawnBlockBreakParticles(session, direction, vector, breakingBlockState);
|
||||
|
||||
double breakTime = BlockUtils.getSessionBreakTime(session, breakingBlockState.block()) * 20;
|
||||
// If the block is custom, we must keep track of when it should break ourselves
|
||||
long blockBreakStartTime = session.getBlockBreakStartTime();
|
||||
if (blockBreakStartTime != 0) {
|
||||
long timeSinceStart = System.currentTimeMillis() - blockBreakStartTime;
|
||||
// We need to add a slight delay to the break time, otherwise the client breaks blocks too fast
|
||||
if (timeSinceStart >= (breakTime += 2) * 50) {
|
||||
// Play break sound and particle
|
||||
LevelEventPacket effectPacket = new LevelEventPacket();
|
||||
effectPacket.setPosition(vectorFloat);
|
||||
effectPacket.setType(LevelEvent.PARTICLE_DESTROY_BLOCK);
|
||||
effectPacket.setData(session.getBlockMappings().getBedrockBlockId(breakingBlock));
|
||||
session.sendUpstreamPacket(effectPacket);
|
||||
|
||||
// Break the block
|
||||
ServerboundPlayerActionPacket finishBreakingPacket = new ServerboundPlayerActionPacket(PlayerAction.FINISH_DIGGING,
|
||||
vector, direction, session.getWorldCache().nextPredictionSequence());
|
||||
session.sendDownstreamGamePacket(finishBreakingPacket);
|
||||
session.setBlockBreakStartTime(0);
|
||||
break;
|
||||
}
|
||||
}
|
||||
// Update the break time in the event that player conditions changed (jumping, effects applied)
|
||||
LevelEventPacket updateBreak = new LevelEventPacket();
|
||||
updateBreak.setType(LevelEvent.BLOCK_UPDATE_BREAK);
|
||||
updateBreak.setPosition(vectorFloat);
|
||||
updateBreak.setData((int) (65535 / breakTime));
|
||||
session.sendUpstreamPacket(updateBreak);
|
||||
}
|
||||
case ABORT_BREAK -> {
|
||||
if (session.getGameMode() != GameMode.CREATIVE) {
|
||||
// As of 1.16.210: item frame items are taken out here.
|
||||
// Survival also sends START_BREAK, but by attaching our process here adventure mode also works
|
||||
Entity itemFrameEntity = ItemFrameEntity.getItemFrameEntity(session, vector);
|
||||
if (itemFrameEntity != null) {
|
||||
ServerboundInteractPacket interactPacket = new ServerboundInteractPacket(itemFrameEntity.getEntityId(),
|
||||
InteractAction.ATTACK, Hand.MAIN_HAND, session.isSneaking());
|
||||
session.sendDownstreamGamePacket(interactPacket);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
ServerboundPlayerActionPacket abortBreakingPacket = new ServerboundPlayerActionPacket(PlayerAction.CANCEL_DIGGING, vector, Direction.DOWN, 0);
|
||||
session.sendDownstreamGamePacket(abortBreakingPacket);
|
||||
LevelEventPacket stopBreak = new LevelEventPacket();
|
||||
stopBreak.setType(LevelEvent.BLOCK_STOP_BREAK);
|
||||
stopBreak.setPosition(vector.toFloat());
|
||||
stopBreak.setData(0);
|
||||
session.setBreakingBlock(-1);
|
||||
session.sendUpstreamPacket(stopBreak);
|
||||
}
|
||||
// Handled in BedrockInventoryTransactionTranslator
|
||||
case STOP_BREAK -> {
|
||||
}
|
||||
case DIMENSION_CHANGE_SUCCESS -> {
|
||||
//sometimes the client doesn't feel like loading
|
||||
PlayStatusPacket spawnPacket = new PlayStatusPacket();
|
||||
spawnPacket.setStatus(PlayStatusPacket.Status.PLAYER_SPAWN);
|
||||
session.sendUpstreamPacket(spawnPacket);
|
||||
|
||||
UpdateAttributesPacket attributesPacket = new UpdateAttributesPacket();
|
||||
attributesPacket.setRuntimeEntityId(entity.getGeyserId());
|
||||
attributesPacket.getAttributes().addAll(entity.getAttributes().values());
|
||||
session.sendUpstreamPacket(attributesPacket);
|
||||
}
|
||||
case JUMP -> entity.setOnGround(false); // Increase block break time while jumping
|
||||
case MISSED_SWING -> {
|
||||
// Java edition sends a cooldown when hitting air.
|
||||
// Normally handled by BedrockLevelSoundEventTranslator, but there is no sound on Java for this.
|
||||
CooldownUtils.sendCooldown(session);
|
||||
|
||||
// TODO Re-evaluate after pre-1.20.10 is no longer supported?
|
||||
if (session.getArmAnimationTicks() == -1) {
|
||||
session.sendDownstreamGamePacket(new ServerboundSwingPacket(Hand.MAIN_HAND));
|
||||
session.activateArmAnimationTicking();
|
||||
|
||||
// Send packet to Bedrock so it knows
|
||||
AnimatePacket animatePacket = new AnimatePacket();
|
||||
animatePacket.setRuntimeEntityId(session.getPlayerEntity().getGeyserId());
|
||||
animatePacket.setAction(AnimatePacket.Action.SWING_ARM);
|
||||
session.sendUpstreamPacket(animatePacket);
|
||||
}
|
||||
}
|
||||
case START_FLYING -> { // Since 1.20.30
|
||||
if (session.isCanFly()) {
|
||||
if (session.getGameMode() == GameMode.SPECTATOR) {
|
||||
// should already be flying
|
||||
session.sendAdventureSettings();
|
||||
break;
|
||||
}
|
||||
|
||||
if (session.getPlayerEntity().getFlag(EntityFlag.SWIMMING) && session.getCollisionManager().isPlayerInWater()) {
|
||||
// As of 1.18.1, Java Edition cannot fly while in water, but it can fly while crawling
|
||||
// If this isn't present, swimming on a 1.13.2 server and then attempting to fly will put you into a flying/swimming state that is invalid on JE
|
||||
session.sendAdventureSettings();
|
||||
break;
|
||||
}
|
||||
|
||||
session.setFlying(true);
|
||||
session.sendDownstreamGamePacket(new ServerboundPlayerAbilitiesPacket(true));
|
||||
} else {
|
||||
// update whether we can fly
|
||||
session.sendAdventureSettings();
|
||||
// stop flying
|
||||
PlayerActionPacket stopFlyingPacket = new PlayerActionPacket();
|
||||
stopFlyingPacket.setRuntimeEntityId(session.getPlayerEntity().getGeyserId());
|
||||
stopFlyingPacket.setAction(PlayerActionType.STOP_FLYING);
|
||||
stopFlyingPacket.setBlockPosition(Vector3i.ZERO);
|
||||
stopFlyingPacket.setResultPosition(Vector3i.ZERO);
|
||||
stopFlyingPacket.setFace(0);
|
||||
session.sendUpstreamPacket(stopFlyingPacket);
|
||||
}
|
||||
}
|
||||
case STOP_FLYING -> {
|
||||
session.setFlying(false);
|
||||
session.sendDownstreamGamePacket(new ServerboundPlayerAbilitiesPacket(false));
|
||||
}
|
||||
case DIMENSION_CHANGE_REQUEST_OR_CREATIVE_DESTROY_BLOCK -> { // Used by client to get book from lecterns and items from item frame in creative mode since 1.20.70
|
||||
BlockState state = session.getGeyser().getWorldManager().blockAt(session, vector);
|
||||
|
||||
if (state.getValue(Properties.HAS_BOOK, false)) {
|
||||
session.setDroppingLecternBook(true);
|
||||
|
||||
ServerboundUseItemOnPacket blockPacket = new ServerboundUseItemOnPacket(
|
||||
vector,
|
||||
Direction.DOWN,
|
||||
Hand.MAIN_HAND,
|
||||
0, 0, 0,
|
||||
false,
|
||||
session.getWorldCache().nextPredictionSequence());
|
||||
session.sendDownstreamGamePacket(blockPacket);
|
||||
break;
|
||||
}
|
||||
|
||||
Entity itemFrame = ItemFrameEntity.getItemFrameEntity(session, packet.getBlockPosition());
|
||||
if (itemFrame != null) {
|
||||
ServerboundInteractPacket interactPacket = new ServerboundInteractPacket(itemFrame.getEntityId(),
|
||||
InteractAction.ATTACK, Hand.MAIN_HAND, session.isSneaking());
|
||||
session.sendDownstreamGamePacket(interactPacket);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void spawnBlockBreakParticles(GeyserSession session, Direction direction, Vector3i position, BlockState blockState) {
|
||||
LevelEventPacket levelEventPacket = new LevelEventPacket();
|
||||
switch (direction) {
|
||||
case UP -> levelEventPacket.setType(LevelEvent.PARTICLE_BREAK_BLOCK_UP);
|
||||
case DOWN -> levelEventPacket.setType(LevelEvent.PARTICLE_BREAK_BLOCK_DOWN);
|
||||
case NORTH -> levelEventPacket.setType(LevelEvent.PARTICLE_BREAK_BLOCK_NORTH);
|
||||
case EAST -> levelEventPacket.setType(LevelEvent.PARTICLE_BREAK_BLOCK_EAST);
|
||||
case SOUTH -> levelEventPacket.setType(LevelEvent.PARTICLE_BREAK_BLOCK_SOUTH);
|
||||
case WEST -> levelEventPacket.setType(LevelEvent.PARTICLE_BREAK_BLOCK_WEST);
|
||||
}
|
||||
levelEventPacket.setPosition(position.toFloat());
|
||||
levelEventPacket.setData(session.getBlockMappings().getBedrockBlock(blockState).getRuntimeId());
|
||||
session.sendUpstreamPacket(levelEventPacket);
|
||||
}
|
||||
|
||||
private void sendPlayerGlideToggle(GeyserSession session, Entity entity) {
|
||||
ServerboundPlayerCommandPacket glidePacket = new ServerboundPlayerCommandPacket(entity.getEntityId(), PlayerState.START_ELYTRA_FLYING);
|
||||
session.sendDownstreamGamePacket(glidePacket);
|
||||
}
|
||||
}
|
Einige Dateien werden nicht angezeigt, da zu viele Dateien in diesem Diff geändert wurden Mehr anzeigen
Laden…
In neuem Issue referenzieren
Einen Benutzer sperren