3
0
Mirror von https://github.com/GeyserMC/Geyser.git synchronisiert 2024-11-20 06:50:09 +01:00

Merge remote-tracking branch 'upstream/dev' into client-vehicle

Dieser Commit ist enthalten in:
AJ Ferguson 2024-05-17 19:06:08 -04:00
Commit 91574efdb6
74 geänderte Dateien mit 4032 neuen und 395 gelöschten Zeilen

Datei anzeigen

@ -4,6 +4,12 @@ dependencies {
isTransitive = false isTransitive = false
} }
implementation(libs.erosion.bukkit.nms) {
attributes {
attribute(TargetJvmVersion.TARGET_JVM_VERSION_ATTRIBUTE, 21)
}
}
implementation(variantOf(libs.adapters.spigot) { implementation(variantOf(libs.adapters.spigot) {
classifier("all") // otherwise the unshaded jar is used without the shaded NMS implementations classifier("all") // otherwise the unshaded jar is used without the shaded NMS implementations
}) })

Datei anzeigen

@ -34,6 +34,7 @@ import org.bukkit.event.Listener;
import org.bukkit.event.block.BlockPlaceEvent; import org.bukkit.event.block.BlockPlaceEvent;
import org.geysermc.geyser.GeyserImpl; import org.geysermc.geyser.GeyserImpl;
import org.geysermc.geyser.level.block.BlockStateValues; import org.geysermc.geyser.level.block.BlockStateValues;
import org.geysermc.geyser.level.block.type.Block;
import org.geysermc.geyser.platform.spigot.world.manager.GeyserSpigotWorldManager; import org.geysermc.geyser.platform.spigot.world.manager.GeyserSpigotWorldManager;
import org.geysermc.geyser.registry.BlockRegistries; import org.geysermc.geyser.registry.BlockRegistries;
import org.geysermc.geyser.session.GeyserSession; import org.geysermc.geyser.session.GeyserSession;
@ -59,7 +60,7 @@ public class GeyserSpigotBlockPlaceListener implements Listener {
event.getBlockPlaced().getX(), event.getBlockPlaced().getY(), event.getBlockPlaced().getZ()))); event.getBlockPlaced().getX(), event.getBlockPlaced().getY(), event.getBlockPlaced().getZ())));
} else { } else {
String javaBlockId = event.getBlockPlaced().getBlockData().getAsString(); String javaBlockId = event.getBlockPlaced().getBlockData().getAsString();
placeBlockSoundPacket.setExtraData(session.getBlockMappings().getBedrockBlockId(BlockRegistries.JAVA_IDENTIFIER_TO_ID.get().getOrDefault(javaBlockId, BlockStateValues.JAVA_AIR_ID))); placeBlockSoundPacket.setExtraData(session.getBlockMappings().getBedrockBlockId(BlockRegistries.JAVA_IDENTIFIER_TO_ID.get().getOrDefault(javaBlockId, Block.JAVA_AIR_ID)));
} }
placeBlockSoundPacket.setIdentifier(":"); placeBlockSoundPacket.setIdentifier(":");
session.sendUpstreamPacket(placeBlockSoundPacket); session.sendUpstreamPacket(placeBlockSoundPacket);

Datei anzeigen

@ -34,6 +34,7 @@ import org.geysermc.geyser.adapters.WorldAdapter;
import org.geysermc.geyser.adapters.paper.PaperAdapters; import org.geysermc.geyser.adapters.paper.PaperAdapters;
import org.geysermc.geyser.adapters.spigot.SpigotAdapters; import org.geysermc.geyser.adapters.spigot.SpigotAdapters;
import org.geysermc.geyser.level.block.BlockStateValues; import org.geysermc.geyser.level.block.BlockStateValues;
import org.geysermc.geyser.level.block.type.Block;
import org.geysermc.geyser.session.GeyserSession; import org.geysermc.geyser.session.GeyserSession;
public class GeyserSpigotNativeWorldManager extends GeyserSpigotWorldManager { public class GeyserSpigotNativeWorldManager extends GeyserSpigotWorldManager {
@ -52,7 +53,7 @@ public class GeyserSpigotNativeWorldManager extends GeyserSpigotWorldManager {
public int getBlockAt(GeyserSession session, int x, int y, int z) { public int getBlockAt(GeyserSession session, int x, int y, int z) {
Player player = Bukkit.getPlayer(session.getPlayerEntity().getUsername()); Player player = Bukkit.getPlayer(session.getPlayerEntity().getUsername());
if (player == null) { if (player == null) {
return BlockStateValues.JAVA_AIR_ID; return Block.JAVA_AIR_ID;
} }
return adapter.getBlockAt(player.getWorld(), x, y, z); return adapter.getBlockAt(player.getWorld(), x, y, z);
} }

Datei anzeigen

@ -25,9 +25,7 @@
package org.geysermc.geyser.platform.spigot.world.manager; package org.geysermc.geyser.platform.spigot.world.manager;
import org.geysermc.mcprotocollib.protocol.data.game.entity.player.GameMode; import it.unimi.dsi.fastutil.ints.Int2ObjectMap;
import org.geysermc.mcprotocollib.protocol.data.game.item.component.DataComponents;
import org.geysermc.mcprotocollib.protocol.data.game.level.block.BlockEntityInfo;
import org.bukkit.Bukkit; import org.bukkit.Bukkit;
import org.bukkit.Chunk; import org.bukkit.Chunk;
import org.bukkit.World; import org.bukkit.World;
@ -39,6 +37,7 @@ import org.checkerframework.checker.nullness.qual.Nullable;
import org.cloudburstmc.nbt.NbtMap; import org.cloudburstmc.nbt.NbtMap;
import org.geysermc.erosion.bukkit.BukkitLecterns; import org.geysermc.erosion.bukkit.BukkitLecterns;
import org.geysermc.erosion.bukkit.BukkitUtils; import org.geysermc.erosion.bukkit.BukkitUtils;
import org.geysermc.erosion.bukkit.PickBlockUtils;
import org.geysermc.erosion.bukkit.SchedulerUtils; import org.geysermc.erosion.bukkit.SchedulerUtils;
import org.geysermc.geyser.GeyserImpl; import org.geysermc.geyser.GeyserImpl;
import org.geysermc.geyser.level.GameRule; import org.geysermc.geyser.level.GameRule;
@ -47,6 +46,9 @@ import org.geysermc.geyser.level.block.BlockStateValues;
import org.geysermc.geyser.registry.BlockRegistries; import org.geysermc.geyser.registry.BlockRegistries;
import org.geysermc.geyser.session.GeyserSession; import org.geysermc.geyser.session.GeyserSession;
import org.geysermc.geyser.util.BlockEntityUtils; import org.geysermc.geyser.util.BlockEntityUtils;
import org.geysermc.mcprotocollib.protocol.data.game.entity.player.GameMode;
import org.geysermc.mcprotocollib.protocol.data.game.item.component.DataComponents;
import org.geysermc.mcprotocollib.protocol.data.game.level.block.BlockEntityInfo;
import java.util.List; import java.util.List;
import java.util.Objects; import java.util.Objects;
@ -68,12 +70,12 @@ public class GeyserSpigotWorldManager extends WorldManager {
public int getBlockAt(GeyserSession session, int x, int y, int z) { public int getBlockAt(GeyserSession session, int x, int y, int z) {
Player bukkitPlayer; Player bukkitPlayer;
if ((bukkitPlayer = Bukkit.getPlayer(session.getPlayerEntity().getUsername())) == null) { if ((bukkitPlayer = Bukkit.getPlayer(session.getPlayerEntity().getUsername())) == null) {
return BlockStateValues.JAVA_AIR_ID; return org.geysermc.geyser.level.block.type.Block.JAVA_AIR_ID;
} }
World world = bukkitPlayer.getWorld(); World world = bukkitPlayer.getWorld();
if (!world.isChunkLoaded(x >> 4, z >> 4)) { if (!world.isChunkLoaded(x >> 4, z >> 4)) {
// If the chunk isn't loaded, how could we even be here? // If the chunk isn't loaded, how could we even be here?
return BlockStateValues.JAVA_AIR_ID; return org.geysermc.geyser.level.block.type.Block.JAVA_AIR_ID;
} }
return getBlockNetworkId(world.getBlockAt(x, y, z)); return getBlockNetworkId(world.getBlockAt(x, y, z));
@ -84,9 +86,9 @@ public class GeyserSpigotWorldManager extends WorldManager {
// Terrible behavior, but this is basically what's always been happening behind the scenes anyway. // Terrible behavior, but this is basically what's always been happening behind the scenes anyway.
CompletableFuture<String> blockData = new CompletableFuture<>(); CompletableFuture<String> blockData = new CompletableFuture<>();
Bukkit.getRegionScheduler().execute(this.plugin, block.getLocation(), () -> blockData.complete(block.getBlockData().getAsString())); Bukkit.getRegionScheduler().execute(this.plugin, block.getLocation(), () -> blockData.complete(block.getBlockData().getAsString()));
return BlockRegistries.JAVA_IDENTIFIER_TO_ID.getOrDefault(blockData.join(), BlockStateValues.JAVA_AIR_ID); return BlockRegistries.JAVA_IDENTIFIER_TO_ID.getOrDefault(blockData.join(), org.geysermc.geyser.level.block.type.Block.JAVA_AIR_ID);
} }
return BlockRegistries.JAVA_IDENTIFIER_TO_ID.getOrDefault(block.getBlockData().getAsString(), BlockStateValues.JAVA_AIR_ID); return BlockRegistries.JAVA_IDENTIFIER_TO_ID.getOrDefault(block.getBlockData().getAsString(), org.geysermc.geyser.level.block.type.Block.JAVA_AIR_ID);
} }
@Override @Override
@ -205,17 +207,16 @@ public class GeyserSpigotWorldManager extends WorldManager {
@Override @Override
public @NonNull CompletableFuture<@Nullable DataComponents> getPickItemComponents(GeyserSession session, int x, int y, int z, boolean addNbtData) { public @NonNull CompletableFuture<@Nullable DataComponents> getPickItemComponents(GeyserSession session, int x, int y, int z, boolean addNbtData) {
CompletableFuture<@Nullable DataComponents> future = new CompletableFuture<>();
Player bukkitPlayer; Player bukkitPlayer;
if ((bukkitPlayer = Bukkit.getPlayer(session.getPlayerEntity().getUuid())) == null) { if ((bukkitPlayer = Bukkit.getPlayer(session.getPlayerEntity().getUuid())) == null) {
future.complete(null); return CompletableFuture.completedFuture(null);
return future;
} }
CompletableFuture<Int2ObjectMap<byte[]>> future = new CompletableFuture<>();
Block block = bukkitPlayer.getWorld().getBlockAt(x, y, z); Block block = bukkitPlayer.getWorld().getBlockAt(x, y, z);
// Paper 1.19.3 complains about async access otherwise. // Paper 1.19.3 complains about async access otherwise.
// java.lang.IllegalStateException: Tile is null, asynchronous access? // java.lang.IllegalStateException: Tile is null, asynchronous access?
SchedulerUtils.runTask(this.plugin, () -> future.complete(/*PickBlockUtils.pickBlock(block)*/ null), block); // TODO fix erosion once clear how to handle this SchedulerUtils.runTask(this.plugin, () -> future.complete(PickBlockUtils.pickBlock(block)), block);
return future; return future.thenApply(RAW_TRANSFORMER);
} }
/** /**

Datei anzeigen

@ -45,6 +45,7 @@ import org.cloudburstmc.protocol.bedrock.codec.BedrockCodec;
import org.geysermc.api.Geyser; import org.geysermc.api.Geyser;
import org.geysermc.cumulus.form.Form; import org.geysermc.cumulus.form.Form;
import org.geysermc.cumulus.form.util.FormBuilder; import org.geysermc.cumulus.form.util.FormBuilder;
import org.geysermc.erosion.packet.Packets;
import org.geysermc.floodgate.crypto.AesCipher; import org.geysermc.floodgate.crypto.AesCipher;
import org.geysermc.floodgate.crypto.AesKeyProducer; import org.geysermc.floodgate.crypto.AesKeyProducer;
import org.geysermc.floodgate.crypto.Base64Topping; import org.geysermc.floodgate.crypto.Base64Topping;
@ -77,6 +78,7 @@ import org.geysermc.geyser.scoreboard.ScoreboardUpdater;
import org.geysermc.geyser.session.GeyserSession; import org.geysermc.geyser.session.GeyserSession;
import org.geysermc.geyser.session.PendingMicrosoftAuthentication; import org.geysermc.geyser.session.PendingMicrosoftAuthentication;
import org.geysermc.geyser.session.SessionManager; import org.geysermc.geyser.session.SessionManager;
import org.geysermc.geyser.session.cache.RegistryCache;
import org.geysermc.geyser.skin.FloodgateSkinUploader; import org.geysermc.geyser.skin.FloodgateSkinUploader;
import org.geysermc.geyser.skin.ProvidedSkins; import org.geysermc.geyser.skin.ProvidedSkins;
import org.geysermc.geyser.skin.SkinProvider; import org.geysermc.geyser.skin.SkinProvider;
@ -211,6 +213,8 @@ public class GeyserImpl implements GeyserApi {
Registries.init(); Registries.init();
BlockRegistries.init(); BlockRegistries.init();
RegistryCache.init();
/* Initialize translators */ /* Initialize translators */
EntityDefinitions.init(); EntityDefinitions.init();
MessageTranslator.init(); MessageTranslator.init();
@ -252,6 +256,17 @@ public class GeyserImpl implements GeyserApi {
} }
VersionCheckUtils.checkForOutdatedJava(logger); VersionCheckUtils.checkForOutdatedJava(logger);
for (int i = 0; i < BlockRegistries.JAVA_BLOCKS.get().length; i++) {
String cleanIdentifier = BlockRegistries.JAVA_BLOCKS.get(i).getCleanJavaIdentifier();
String newIdentifier = BlockRegistries.BLOCK_STATES.get(i).block().javaIdentifier();
if (!cleanIdentifier.equals(newIdentifier)) {
System.out.println("Check block " + BlockRegistries.BLOCK_STATES.get(i).block().javaIdentifier());
break;
}
}
System.out.println(BlockRegistries.JAVA_BLOCKS.get().length);
System.out.println(BlockRegistries.BLOCK_STATES.get().size());
} }
private void startInstance() { private void startInstance() {
@ -383,7 +398,7 @@ public class GeyserImpl implements GeyserApi {
this.newsHandler = new NewsHandler(BRANCH, this.buildNumber()); this.newsHandler = new NewsHandler(BRANCH, this.buildNumber());
//Packets.initGeyser(); Packets.initGeyser();
if (Epoll.isAvailable()) { if (Epoll.isAvailable()) {
this.erosionUnixListener = new UnixSocketClientListener(); this.erosionUnixListener = new UnixSocketClientListener();

Datei anzeigen

@ -135,7 +135,7 @@ public class Entity implements GeyserEntity {
this.valid = false; this.valid = false;
this.propertyManager = new GeyserEntityPropertyManager(definition.registeredProperties()); this.propertyManager = definition.registeredProperties() == null ? null : new GeyserEntityPropertyManager(definition.registeredProperties());
setPosition(position); setPosition(position);
setAirSupply(getMaxAir()); setAirSupply(getMaxAir());
@ -369,7 +369,7 @@ public class Entity implements GeyserEntity {
return; return;
} }
if (propertyManager.hasProperties()) { if (propertyManager != null && propertyManager.hasProperties()) {
SetEntityDataPacket entityDataPacket = new SetEntityDataPacket(); SetEntityDataPacket entityDataPacket = new SetEntityDataPacket();
entityDataPacket.setRuntimeEntityId(geyserId); entityDataPacket.setRuntimeEntityId(geyserId);
propertyManager.applyIntProperties(entityDataPacket.getProperties().getIntProperties()); propertyManager.applyIntProperties(entityDataPacket.getProperties().getIntProperties());

Datei anzeigen

@ -33,6 +33,7 @@ import org.geysermc.erosion.util.BlockPositionIterator;
import org.geysermc.geyser.entity.EntityDefinitions; import org.geysermc.geyser.entity.EntityDefinitions;
import org.geysermc.geyser.entity.type.player.PlayerEntity; import org.geysermc.geyser.entity.type.player.PlayerEntity;
import org.geysermc.geyser.level.block.BlockStateValues; import org.geysermc.geyser.level.block.BlockStateValues;
import org.geysermc.geyser.level.block.type.Block;
import org.geysermc.geyser.level.physics.BoundingBox; import org.geysermc.geyser.level.physics.BoundingBox;
import org.geysermc.geyser.session.GeyserSession; import org.geysermc.geyser.session.GeyserSession;
import org.geysermc.geyser.translator.collision.BlockCollision; import org.geysermc.geyser.translator.collision.BlockCollision;
@ -162,7 +163,7 @@ public class FishingHookEntity extends ThrowableEntity {
*/ */
protected boolean isInAir() { protected boolean isInAir() {
int block = session.getGeyser().getWorldManager().getBlockAt(session, position.toInt()); int block = session.getGeyser().getWorldManager().getBlockAt(session, position.toInt());
return block == BlockStateValues.JAVA_AIR_ID; return block == Block.JAVA_AIR_ID;
} }
@Override @Override

Datei anzeigen

@ -25,8 +25,6 @@
package org.geysermc.geyser.erosion; package org.geysermc.geyser.erosion;
import org.geysermc.mcprotocollib.protocol.data.game.item.component.DataComponents;
import org.geysermc.mcprotocollib.protocol.data.game.level.block.value.PistonValueType;
import io.netty.channel.Channel; import io.netty.channel.Channel;
import it.unimi.dsi.fastutil.ints.Int2ObjectMap; import it.unimi.dsi.fastutil.ints.Int2ObjectMap;
import it.unimi.dsi.fastutil.ints.Int2ObjectMaps; import it.unimi.dsi.fastutil.ints.Int2ObjectMaps;
@ -43,21 +41,16 @@ import org.geysermc.erosion.packet.ErosionPacketHandler;
import org.geysermc.erosion.packet.ErosionPacketSender; import org.geysermc.erosion.packet.ErosionPacketSender;
import org.geysermc.erosion.packet.backendbound.BackendboundInitializePacket; import org.geysermc.erosion.packet.backendbound.BackendboundInitializePacket;
import org.geysermc.erosion.packet.backendbound.BackendboundPacket; import org.geysermc.erosion.packet.backendbound.BackendboundPacket;
import org.geysermc.erosion.packet.geyserbound.GeyserboundBatchBlockIdPacket; import org.geysermc.erosion.packet.geyserbound.*;
import org.geysermc.erosion.packet.geyserbound.GeyserboundBlockEntityPacket;
import org.geysermc.erosion.packet.geyserbound.GeyserboundBlockIdPacket;
import org.geysermc.erosion.packet.geyserbound.GeyserboundBlockLookupFailPacket;
import org.geysermc.erosion.packet.geyserbound.GeyserboundBlockPlacePacket;
import org.geysermc.erosion.packet.geyserbound.GeyserboundHandshakePacket;
import org.geysermc.erosion.packet.geyserbound.GeyserboundPickBlockPacket;
import org.geysermc.erosion.packet.geyserbound.GeyserboundPistonEventPacket;
import org.geysermc.geyser.level.block.BlockStateValues; import org.geysermc.geyser.level.block.BlockStateValues;
import org.geysermc.geyser.level.block.type.Block;
import org.geysermc.geyser.level.physics.Direction; import org.geysermc.geyser.level.physics.Direction;
import org.geysermc.geyser.network.GameProtocol; import org.geysermc.geyser.network.GameProtocol;
import org.geysermc.geyser.session.GeyserSession; import org.geysermc.geyser.session.GeyserSession;
import org.geysermc.geyser.session.cache.PistonCache; import org.geysermc.geyser.session.cache.PistonCache;
import org.geysermc.geyser.translator.level.block.entity.PistonBlockEntity; import org.geysermc.geyser.translator.level.block.entity.PistonBlockEntity;
import org.geysermc.geyser.util.BlockEntityUtils; import org.geysermc.geyser.util.BlockEntityUtils;
import org.geysermc.mcprotocollib.protocol.data.game.level.block.value.PistonValueType;
import java.util.concurrent.CompletableFuture; import java.util.concurrent.CompletableFuture;
import java.util.concurrent.atomic.AtomicInteger; import java.util.concurrent.atomic.AtomicInteger;
@ -71,7 +64,7 @@ public final class GeyserboundPacketHandlerImpl extends AbstractGeyserboundPacke
@Setter @Setter
private CompletableFuture<int[]> pendingBatchLookup = null; private CompletableFuture<int[]> pendingBatchLookup = null;
@Setter @Setter
private CompletableFuture<DataComponents> pickBlockLookup = null; private CompletableFuture<Int2ObjectMap<byte[]>> pickBlockLookup = null;
private final AtomicInteger nextTransactionId = new AtomicInteger(1); private final AtomicInteger nextTransactionId = new AtomicInteger(1);
@ -127,7 +120,7 @@ public final class GeyserboundPacketHandlerImpl extends AbstractGeyserboundPacke
} }
CompletableFuture<Integer> future = this.asyncPendingLookups.remove(transactionId); CompletableFuture<Integer> future = this.asyncPendingLookups.remove(transactionId);
if (future != null) { if (future != null) {
future.complete(BlockStateValues.JAVA_AIR_ID); future.complete(Block.JAVA_AIR_ID);
} }
} }
@ -147,7 +140,7 @@ public final class GeyserboundPacketHandlerImpl extends AbstractGeyserboundPacke
@Override @Override
public void handlePickBlock(GeyserboundPickBlockPacket packet) { public void handlePickBlock(GeyserboundPickBlockPacket packet) {
if (this.pickBlockLookup != null) { if (this.pickBlockLookup != null) {
//this.pickBlockLookup.complete(packet.getTag()); // TODO 1.20.5 this.pickBlockLookup.complete(packet.getComponents());
} }
} }

Datei anzeigen

@ -25,6 +25,7 @@
package org.geysermc.geyser.level; package org.geysermc.geyser.level;
import it.unimi.dsi.fastutil.ints.Int2ObjectMap;
import it.unimi.dsi.fastutil.objects.Object2ObjectMap; import it.unimi.dsi.fastutil.objects.Object2ObjectMap;
import it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap; import it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap;
import it.unimi.dsi.fastutil.objects.ObjectArrayList; import it.unimi.dsi.fastutil.objects.ObjectArrayList;
@ -179,9 +180,9 @@ public class GeyserWorldManager extends WorldManager {
if (erosionHandler == null) { if (erosionHandler == null) {
return super.getPickItemComponents(session, x, y, z, addNbtData); return super.getPickItemComponents(session, x, y, z, addNbtData);
} }
CompletableFuture<DataComponents> future = new CompletableFuture<>(); CompletableFuture<Int2ObjectMap<byte[]>> future = new CompletableFuture<>();
erosionHandler.setPickBlockLookup(future); erosionHandler.setPickBlockLookup(future);
erosionHandler.sendPacket(new BackendboundPickBlockPacket(Vector3i.from(x, y, z))); erosionHandler.sendPacket(new BackendboundPickBlockPacket(Vector3i.from(x, y, z)));
return future; return future.thenApply(RAW_TRANSFORMER);
} }
} }

Datei anzeigen

@ -25,19 +25,29 @@
package org.geysermc.geyser.level; package org.geysermc.geyser.level;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import it.unimi.dsi.fastutil.ints.Int2ObjectMap;
import it.unimi.dsi.fastutil.ints.Int2ObjectMaps;
import org.checkerframework.checker.nullness.qual.NonNull; import org.checkerframework.checker.nullness.qual.NonNull;
import org.checkerframework.checker.nullness.qual.Nullable; import org.checkerframework.checker.nullness.qual.Nullable;
import org.cloudburstmc.math.vector.Vector3i; import org.cloudburstmc.math.vector.Vector3i;
import org.geysermc.erosion.util.BlockPositionIterator; import org.geysermc.erosion.util.BlockPositionIterator;
import org.geysermc.geyser.session.GeyserSession; import org.geysermc.geyser.session.GeyserSession;
import org.geysermc.mcprotocollib.protocol.data.game.entity.player.GameMode; import org.geysermc.mcprotocollib.protocol.data.game.entity.player.GameMode;
import org.geysermc.mcprotocollib.protocol.data.game.item.component.DataComponent;
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.DataComponents;
import org.geysermc.mcprotocollib.protocol.data.game.item.component.ItemCodecHelper;
import org.geysermc.mcprotocollib.protocol.data.game.level.block.BlockEntityInfo; import org.geysermc.mcprotocollib.protocol.data.game.level.block.BlockEntityInfo;
import org.geysermc.mcprotocollib.protocol.data.game.setting.Difficulty; import org.geysermc.mcprotocollib.protocol.data.game.setting.Difficulty;
import java.util.HashMap;
import java.util.List; import java.util.List;
import java.util.Locale; import java.util.Locale;
import java.util.Map;
import java.util.concurrent.CompletableFuture; import java.util.concurrent.CompletableFuture;
import java.util.function.Function;
/** /**
* Class that manages or retrieves various information * Class that manages or retrieves various information
@ -223,4 +233,20 @@ public abstract class WorldManager {
public CompletableFuture<@Nullable DataComponents> getPickItemComponents(GeyserSession session, int x, int y, int z, boolean addExtraData) { public CompletableFuture<@Nullable DataComponents> getPickItemComponents(GeyserSession session, int x, int y, int z, boolean addExtraData) {
return CompletableFuture.completedFuture(null); return CompletableFuture.completedFuture(null);
} }
protected static final Function<Int2ObjectMap<byte[]>, DataComponents> RAW_TRANSFORMER = map -> {
try {
Map<DataComponentType<?>, DataComponent<?, ?>> components = new HashMap<>();
Int2ObjectMaps.fastForEach(map, entry -> {
DataComponentType type = DataComponentType.from(entry.getIntKey());
ByteBuf buf = Unpooled.wrappedBuffer(entry.getValue());
DataComponent value = type.readDataComponent(ItemCodecHelper.INSTANCE, buf);
components.put(type, value);
});
return new DataComponents(components);
} catch (Exception e) {
e.printStackTrace();
return null;
}
};
} }

Datei anzeigen

@ -30,6 +30,7 @@ import it.unimi.dsi.fastutil.ints.*;
import it.unimi.dsi.fastutil.objects.Object2IntMap; import it.unimi.dsi.fastutil.objects.Object2IntMap;
import it.unimi.dsi.fastutil.objects.Object2IntOpenHashMap; import it.unimi.dsi.fastutil.objects.Object2IntOpenHashMap;
import org.checkerframework.checker.nullness.qual.Nullable; import org.checkerframework.checker.nullness.qual.Nullable;
import org.geysermc.geyser.level.block.type.Block;
import org.geysermc.geyser.level.physics.Direction; import org.geysermc.geyser.level.physics.Direction;
import org.geysermc.geyser.level.physics.PistonBehavior; import org.geysermc.geyser.level.physics.PistonBehavior;
import org.geysermc.geyser.registry.BlockRegistries; import org.geysermc.geyser.registry.BlockRegistries;
@ -49,7 +50,6 @@ public final class BlockStateValues {
private static final Int2IntMap BANNER_COLORS = new FixedInt2IntMap(); private static final Int2IntMap BANNER_COLORS = new FixedInt2IntMap();
private static final Int2ByteMap BED_COLORS = new FixedInt2ByteMap(); private static final Int2ByteMap BED_COLORS = new FixedInt2ByteMap();
private static final Int2IntMap BRUSH_PROGRESS = new Int2IntOpenHashMap(); private static final Int2IntMap BRUSH_PROGRESS = new Int2IntOpenHashMap();
private static final Int2ByteMap COMMAND_BLOCK_VALUES = new Int2ByteOpenHashMap();
private static final Int2ObjectMap<DoubleChestValue> DOUBLE_CHEST_VALUES = new Int2ObjectOpenHashMap<>(); private static final Int2ObjectMap<DoubleChestValue> DOUBLE_CHEST_VALUES = new Int2ObjectOpenHashMap<>();
private static final Int2ObjectMap<String> FLOWER_POT_VALUES = new Int2ObjectOpenHashMap<>(); private static final Int2ObjectMap<String> FLOWER_POT_VALUES = new Int2ObjectOpenHashMap<>();
private static final IntSet HORIZONTAL_FACING_JIGSAWS = new IntOpenHashSet(); private static final IntSet HORIZONTAL_FACING_JIGSAWS = new IntOpenHashSet();
@ -83,10 +83,6 @@ public final class BlockStateValues {
public static int JAVA_SLIME_BLOCK_ID; public static int JAVA_SLIME_BLOCK_ID;
public static int JAVA_SPAWNER_ID; public static int JAVA_SPAWNER_ID;
public static int JAVA_WATER_ID; public static int JAVA_WATER_ID;
public static int JAVA_BUBBLE_COLUMN_DRAG_ID;
public static int JAVA_BUBBLE_COLUMN_UPWARD_ID;
public static int JAVA_SOUL_SAND_ID;
public static int JAVA_ICE_ID;
public static final int NUM_FLUID_LEVELS = 9; public static final int NUM_FLUID_LEVELS = 9;
@ -119,11 +115,6 @@ public final class BlockStateValues {
} }
} }
if (javaId.contains("command_block")) {
COMMAND_BLOCK_VALUES.put(javaBlockState, javaId.contains("conditional=true") ? (byte) 1 : (byte) 0);
return;
}
if (blockData.get("double_chest_position") != null) { if (blockData.get("double_chest_position") != null) {
boolean isX = (blockData.get("x") != null); boolean isX = (blockData.get("x") != null);
boolean isDirectionPositive = ((blockData.get("x") != null && blockData.get("x").asBoolean()) || boolean isDirectionPositive = ((blockData.get("x") != null && blockData.get("x").asBoolean()) ||
@ -234,7 +225,7 @@ public final class BlockStateValues {
ALL_CAULDRONS.add(javaBlockState); ALL_CAULDRONS.add(javaBlockState);
} }
if (javaId.contains("_cauldron") && !javaId.contains("water_")) { if (javaId.contains("_cauldron") && !javaId.contains("water_")) {
NON_WATER_CAULDRONS.add(javaBlockState); NON_WATER_CAULDRONS.add(javaBlockState);
} }
if (javaId.contains("vine") || javaId.startsWith("minecraft:ladder") || javaId.startsWith("minecraft:scaffolding")) { if (javaId.contains("vine") || javaId.startsWith("minecraft:ladder") || javaId.startsWith("minecraft:scaffolding")) {
@ -305,16 +296,6 @@ public final class BlockStateValues {
return ALL_CAULDRONS.contains(state); return ALL_CAULDRONS.contains(state);
} }
/**
* The block state in Java and Bedrock both contain the conditional bit, however command block block entity tags
* in Bedrock need the conditional information.
*
* @return the list of all command blocks and if they are conditional (1 or 0)
*/
public static Int2ByteMap getCommandBlockValues() {
return COMMAND_BLOCK_VALUES;
}
/** /**
* All double chest values are part of the block state in Java and part of the block entity tag in Bedrock. * All double chest values are part of the block state in Java and part of the block entity tag in Bedrock.
* This gives the DoubleChestValue that can be calculated into the final tag. * This gives the DoubleChestValue that can be calculated into the final tag.
@ -384,7 +365,7 @@ public final class BlockStateValues {
* @return Block state for the piston head * @return Block state for the piston head
*/ */
public static int getPistonHead(Direction direction) { public static int getPistonHead(Direction direction) {
return PISTON_HEADS.getOrDefault(direction, BlockStateValues.JAVA_AIR_ID); return PISTON_HEADS.getOrDefault(direction, Block.JAVA_AIR_ID);
} }
/** /**
@ -448,7 +429,7 @@ public final class BlockStateValues {
} }
public static boolean canPistonMoveBlock(int javaId, boolean isPushing) { public static boolean canPistonMoveBlock(int javaId, boolean isPushing) {
if (javaId == JAVA_AIR_ID) { if (javaId == Block.JAVA_AIR_ID) {
return true; return true;
} }
// Pistons can only be moved if they aren't extended // Pistons can only be moved if they aren't extended

Datei-Diff unterdrückt, da er zu groß ist Diff laden

Datei anzeigen

@ -0,0 +1,34 @@
/*
* 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.level.block.property;
public enum ChestType {
SINGLE,
LEFT,
RIGHT;
public static final ChestType[] VALUES = values();
}

Datei anzeigen

@ -0,0 +1,146 @@
/*
* 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.level.block.property;
import org.geysermc.geyser.level.physics.Axis;
import org.geysermc.geyser.level.physics.Direction;
public final class Properties {
public static final Property<Boolean> ATTACHED = Property.create("attached");
public static final Property<Boolean> BOTTOM = Property.create("bottom");
public static final Property<Boolean> CONDITIONAL = Property.create("conditional");
public static final Property<Boolean> DISARMED = Property.create("disarmed");
public static final Property<Boolean> DRAG = Property.create("drag");
public static final Property<Boolean> ENABLED = Property.create("enabled");
public static final Property<Boolean> EXTENDED = Property.create("extended");
public static final Property<Boolean> EYE = Property.create("eye");
public static final Property<Boolean> FALLING = Property.create("falling");
public static final Property<Boolean> HANGING = Property.create("hanging");
public static final Property<Boolean> HAS_BOTTLE_0 = Property.create("has_bottle_0");
public static final Property<Boolean> HAS_BOTTLE_1 = Property.create("has_bottle_1");
public static final Property<Boolean> HAS_BOTTLE_2 = Property.create("has_bottle_2");
public static final Property<Boolean> HAS_RECORD = Property.create("has_record");
public static final Property<Boolean> HAS_BOOK = Property.create("has_book");
public static final Property<Boolean> INVERTED = Property.create("inverted");
public static final Property<Boolean> IN_WALL = Property.create("in_wall");
public static final Property<Boolean> LIT = Property.create("lit");
public static final Property<Boolean> LOCKED = Property.create("locked");
public static final Property<Boolean> OCCUPIED = Property.create("occupied");
public static final Property<Boolean> OPEN = Property.create("open");
public static final Property<Boolean> PERSISTENT = Property.create("persistent");
public static final Property<Boolean> POWERED = Property.create("powered");
public static final Property<Boolean> SHORT = Property.create("short");
public static final Property<Boolean> SIGNAL_FIRE = Property.create("signal_fire");
public static final Property<Boolean> SNOWY = Property.create("snowy");
public static final Property<Boolean> TRIGGERED = Property.create("triggered");
public static final Property<Boolean> UNSTABLE = Property.create("unstable");
public static final Property<Boolean> WATERLOGGED = Property.create("waterlogged");
public static final Property<Boolean> BERRIES = Property.create("berries");
public static final Property<Boolean> BLOOM = Property.create("bloom");
public static final Property<Boolean> SHRIEKING = Property.create("shrieking");
public static final Property<Boolean> CAN_SUMMON = Property.create("can_summon");
public static final Property<Axis> HORIZONTAL_AXIS = Property.create("axis");
public static final Property<Axis> AXIS = Property.create("axis");
public static final Property<Boolean> UP = Property.create("up");
public static final Property<Boolean> DOWN = Property.create("down");
public static final Property<Boolean> NORTH = Property.create("north");
public static final Property<Boolean> EAST = Property.create("east");
public static final Property<Boolean> SOUTH = Property.create("south");
public static final Property<Boolean> WEST = Property.create("west");
public static final Property<Direction> FACING = Property.create("facing");
public static final Property<Direction> FACING_HOPPER = Property.create("facing");
public static final Property<Direction> HORIZONTAL_FACING = Property.create("facing");
public static final Property<Integer> FLOWER_AMOUNT = Property.create("flower_amount");
public static final Property<String> ORIENTATION = Property.create("orientation");
public static final Property<String> ATTACH_FACE = Property.create("face");
public static final Property<String> BELL_ATTACHMENT = Property.create("attachment");
public static final Property<String> EAST_WALL = Property.create("east");
public static final Property<String> NORTH_WALL = Property.create("north");
public static final Property<String> SOUTH_WALL = Property.create("south");
public static final Property<String> WEST_WALL = Property.create("west");
public static final Property<String> EAST_REDSTONE = Property.create("east");
public static final Property<String> NORTH_REDSTONE = Property.create("north");
public static final Property<String> SOUTH_REDSTONE = Property.create("south");
public static final Property<String> WEST_REDSTONE = Property.create("west");
public static final Property<String> DOUBLE_BLOCK_HALF = Property.create("half");
public static final Property<String> HALF = Property.create("half");
public static final Property<String> RAIL_SHAPE = Property.create("shape");
public static final Property<String> RAIL_SHAPE_STRAIGHT = Property.create("shape");
public static final Property<Integer> AGE_1 = Property.create("age");
public static final Property<Integer> AGE_2 = Property.create("age");
public static final Property<Integer> AGE_3 = Property.create("age");
public static final Property<Integer> AGE_4 = Property.create("age");
public static final Property<Integer> AGE_5 = Property.create("age");
public static final Property<Integer> AGE_7 = Property.create("age");
public static final Property<Integer> AGE_15 = Property.create("age");
public static final Property<Integer> AGE_25 = Property.create("age");
public static final Property<Integer> BITES = Property.create("bites");
public static final Property<Integer> CANDLES = Property.create("candles");
public static final Property<Integer> DELAY = Property.create("delay");
public static final Property<Integer> DISTANCE = Property.create("distance");
public static final Property<Integer> EGGS = Property.create("eggs");
public static final Property<Integer> HATCH = Property.create("hatch");
public static final Property<Integer> LAYERS = Property.create("layers");
public static final Property<Integer> LEVEL_CAULDRON = Property.create("level");
public static final Property<Integer> LEVEL_COMPOSTER = Property.create("level");
public static final Property<Integer> LEVEL_FLOWING = Property.create("level");
public static final Property<Integer> LEVEL_HONEY = Property.create("honey_level");
public static final Property<Integer> LEVEL = Property.create("level");
public static final Property<Integer> MOISTURE = Property.create("moisture");
public static final Property<Integer> NOTE = Property.create("note");
public static final Property<Integer> PICKLES = Property.create("pickles");
public static final Property<Integer> POWER = Property.create("power");
public static final Property<Integer> STAGE = Property.create("stage");
public static final Property<Integer> STABILITY_DISTANCE = Property.create("distance");
public static final Property<Integer> RESPAWN_ANCHOR_CHARGES = Property.create("charges");
public static final Property<Integer> ROTATION_16 = Property.create("rotation");
public static final Property<String> BED_PART = Property.create("part");
public static final Property<String> CHEST_TYPE = Property.create("type");
public static final Property<String> MODE_COMPARATOR = Property.create("mode");
public static final Property<String> DOOR_HINGE = Property.create("hinge");
public static final Property<String> NOTEBLOCK_INSTRUMENT = Property.create("instrument");
public static final Property<String> PISTON_TYPE = Property.create("type");
public static final Property<String> SLAB_TYPE = Property.create("type");
public static final Property<String> STAIRS_SHAPE = Property.create("shape");
public static final Property<String> STRUCTUREBLOCK_MODE = Property.create("mode");
public static final Property<String> BAMBOO_LEAVES = Property.create("leaves");
public static final Property<String> TILT = Property.create("tilt");
public static final Property<Direction> VERTICAL_DIRECTION = Property.create("vertical_direction");
public static final Property<String> DRIPSTONE_THICKNESS = Property.create("thickness");
public static final Property<String> SCULK_SENSOR_PHASE = Property.create("sculk_sensor_phase");
public static final Property<Boolean> CHISELED_BOOKSHELF_SLOT_0_OCCUPIED = Property.create("slot_0_occupied");
public static final Property<Boolean> CHISELED_BOOKSHELF_SLOT_1_OCCUPIED = Property.create("slot_1_occupied");
public static final Property<Boolean> CHISELED_BOOKSHELF_SLOT_2_OCCUPIED = Property.create("slot_2_occupied");
public static final Property<Boolean> CHISELED_BOOKSHELF_SLOT_3_OCCUPIED = Property.create("slot_3_occupied");
public static final Property<Boolean> CHISELED_BOOKSHELF_SLOT_4_OCCUPIED = Property.create("slot_4_occupied");
public static final Property<Boolean> CHISELED_BOOKSHELF_SLOT_5_OCCUPIED = Property.create("slot_5_occupied");
public static final Property<Integer> DUSTED = Property.create("dusted");
public static final Property<Boolean> CRACKED = Property.create("cracked");
public static final Property<Boolean> CRAFTING = Property.create("crafting");
public static final Property<String> TRIAL_SPAWNER_STATE = Property.create("trial_spawner_state");
public static final Property<String> VAULT_STATE = Property.create("vault_state");
public static final Property<Boolean> OMINOUS = Property.create("ominous");
}

Datei anzeigen

@ -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.level.block.property;
public class Property<T extends Comparable<T>> {
private final String name;
public Property(String name) {
this.name = name;
}
@Override
public String toString() {
return getClass().getSimpleName() + "[" + name + "]";
}
public static <T extends Comparable<T>> Property<T> create(String name) {
return new Property<>(name);
}
}

Datei anzeigen

@ -0,0 +1,39 @@
/*
* 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.level.block.type;
public class BannerBlock extends Block {
private final int dyeColor;
public BannerBlock(String javaIdentifier, int dyeColor, Builder builder) {
super(javaIdentifier, builder);
this.dyeColor = dyeColor;
}
public int dyeColor() {
return dyeColor;
}
}

Datei anzeigen

@ -0,0 +1,39 @@
/*
* 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.level.block.type;
public class BedBlock extends Block {
private final int dyeColor;
public BedBlock(String javaIdentifier, int dyeColor, Builder builder) {
super(javaIdentifier, builder);
this.dyeColor = dyeColor;
}
public int dyeColor() {
return dyeColor;
}
}

Datei anzeigen

@ -0,0 +1,188 @@
/*
* 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.level.block.type;
import it.unimi.dsi.fastutil.Pair;
import it.unimi.dsi.fastutil.ints.IntArrayList;
import it.unimi.dsi.fastutil.ints.IntList;
import it.unimi.dsi.fastutil.objects.Reference2ObjectArrayMap;
import it.unimi.dsi.fastutil.objects.Reference2ObjectMap;
import org.geysermc.geyser.level.block.property.Property;
import org.geysermc.geyser.registry.BlockRegistries;
import org.geysermc.mcprotocollib.protocol.data.game.Identifier;
import java.util.*;
import java.util.stream.Stream;
public class Block {
public static final int JAVA_AIR_ID = 0;
private final String javaIdentifier;
private final boolean requiresCorrectToolForDrops;
private final boolean hasBlockEntity;
private final float destroyTime;
private int javaId = -1;
public Block(String javaIdentifier, Builder builder) {
this.javaIdentifier = Identifier.formalize(javaIdentifier).intern();
this.requiresCorrectToolForDrops = builder.requiresCorrectToolForDrops;
this.hasBlockEntity = builder.hasBlockEntity;
this.destroyTime = builder.destroyTime;
builder.build(this);
}
public String javaIdentifier() {
return javaIdentifier;
}
public boolean requiresCorrectToolForDrops() {
return requiresCorrectToolForDrops;
}
public boolean hasBlockEntity() {
return hasBlockEntity;
}
public float destroyTime() {
return destroyTime;
}
public int javaId() {
return javaId;
}
public void setJavaId(int javaId) {
if (this.javaId != -1) {
throw new RuntimeException("Block ID has already been set!");
}
this.javaId = javaId;
}
@Override
public String toString() {
return "Item{" +
"javaIdentifier='" + javaIdentifier + '\'' +
", javaId=" + javaId +
'}';
}
public static Builder builder() {
return new Builder();
}
public static final class Builder {
private final Map<Property<?>, List<Comparable<?>>> states = new LinkedHashMap<>();
private boolean requiresCorrectToolForDrops = false;
private boolean hasBlockEntity = false;
private float destroyTime;
/**
* For states that we're just tracking for mirroring Java states.
*/
public Builder enumState(Property<String> property, String... values) {
states.put(property, List.of(values));
return this;
}
@SafeVarargs
public final <T extends Enum<T>> Builder enumState(Property<T> property, T... enums) {
states.put(property, List.of(enums));
return this;
}
public Builder booleanState(Property<Boolean> property) {
states.put(property, List.of(Boolean.TRUE, Boolean.FALSE)); // Make this list a static constant if it'll survive past initialization
return this;
}
public Builder intState(Property<Integer> property, int low, int high) {
IntList list = new IntArrayList();
// There is a state for every number between the low and high.
for (int i = low; i <= high; i++) {
list.add(i);
}
states.put(property, List.copyOf(list)); // Boxing reasons for that copy I guess.
return this;
}
public Builder requiresCorrectToolForDrops() {
this.requiresCorrectToolForDrops = true;
return this;
}
public Builder setBlockEntity() {
this.hasBlockEntity = true;
return this;
}
public Builder destroyTime(float destroyTime) {
this.destroyTime = destroyTime;
return this;
}
private void build(Block block) {
if (states.isEmpty()) {
BlockRegistries.BLOCK_STATES.get().add(new BlockState(block, BlockRegistries.BLOCK_STATES.get().size()));
} else {
// Think of this stream as another list containing, at the start, one empty list.
// It's two collections. Not a stream from the empty list.
Stream<List<Pair<Property<?>, Comparable<?>>>> stream = Stream.of(Collections.emptyList());
for (var state : this.states.entrySet()) {
// OK, so here's how I understand this works. Because this was staring at vanilla Java code trying
// to figure out exactly how it works so we don't have any discrepencies.
// For each existing pair in the list, a new list is created, adding one of the new values.
// Property up [true/false] would exist as true and false
// Both entries will get duplicated, adding down, true and false.
stream = stream.flatMap(aPreviousPropertiesList ->
// So the above is a list. It may be empty if this is the first property,
// or it may be populated if this is not the first property.
// We're about to create a new stream, each with a new list,
// for every previous property
state.getValue().stream().map(value -> {
var newProperties = new ArrayList<>(aPreviousPropertiesList);
newProperties.add(Pair.of(state.getKey(), value));
return newProperties;
}));
}
// Now we have a list of Pair<Property, Value>s. Each list is a block state!
// If we have two boolean properties: up [true/false] and down [true/false],
// We'll see [up=true,down=true], [up=false,down=true], [up=true,down=false], [up=false,down=false]
stream.forEach(properties -> {
Reference2ObjectMap<Property<?>, Comparable<?>> propertyMap = new Reference2ObjectArrayMap<>(properties.size());
for (int i = 0; i < properties.size(); i++) {
Pair<Property<?>, Comparable<?>> property = properties.get(i);
propertyMap.put(property.key(), property.value());
}
BlockRegistries.BLOCK_STATES.get().add(new BlockState(block, BlockRegistries.BLOCK_STATES.get().size(), propertyMap));
});
}
}
private Builder() {
}
}
}

Datei anzeigen

@ -0,0 +1,64 @@
/*
* 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.level.block.type;
import it.unimi.dsi.fastutil.objects.Reference2ObjectMap;
import it.unimi.dsi.fastutil.objects.Reference2ObjectMaps;
import org.geysermc.geyser.level.block.property.Property;
import org.geysermc.geyser.registry.BlockRegistries;
public final class BlockState {
private final Block block;
private final int javaId;
private final Reference2ObjectMap<Property<?>, Comparable<?>> states;
BlockState(Block block, int javaId) {
this(block, javaId, Reference2ObjectMaps.emptyMap());
}
BlockState(Block block, int javaId, Reference2ObjectMap<Property<?>, Comparable<?>> states) {
this.block = block;
this.javaId = javaId;
this.states = states;
}
public <T extends Comparable<T>> T getValue(Property<T> property) {
//noinspection unchecked
return (T) states.get(property);
}
public Block block() {
return block;
}
public int javaId() {
return javaId;
}
public static BlockState of(int javaId) {
return BlockRegistries.BLOCK_STATES.get(javaId);
}
}

Datei anzeigen

@ -34,6 +34,9 @@ import it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap;
import org.geysermc.geyser.api.block.custom.CustomBlockData; import org.geysermc.geyser.api.block.custom.CustomBlockData;
import org.geysermc.geyser.api.block.custom.CustomBlockState; import org.geysermc.geyser.api.block.custom.CustomBlockState;
import org.geysermc.geyser.api.block.custom.nonvanilla.JavaBlockState; import org.geysermc.geyser.api.block.custom.nonvanilla.JavaBlockState;
import org.geysermc.geyser.level.block.Blocks;
import org.geysermc.geyser.level.block.type.Block;
import org.geysermc.geyser.level.block.type.BlockState;
import org.geysermc.geyser.registry.loader.CollisionRegistryLoader; import org.geysermc.geyser.registry.loader.CollisionRegistryLoader;
import org.geysermc.geyser.registry.loader.RegistryLoaders; import org.geysermc.geyser.registry.loader.RegistryLoaders;
import org.geysermc.geyser.registry.populator.BlockRegistryPopulator; import org.geysermc.geyser.registry.populator.BlockRegistryPopulator;
@ -44,8 +47,8 @@ import org.geysermc.geyser.registry.type.BlockMappings;
import org.geysermc.geyser.registry.type.CustomSkull; import org.geysermc.geyser.registry.type.CustomSkull;
import org.geysermc.geyser.translator.collision.BlockCollision; import org.geysermc.geyser.translator.collision.BlockCollision;
import java.util.ArrayList;
import java.util.BitSet; import java.util.BitSet;
import java.util.Set; import java.util.Set;
/** /**
@ -58,6 +61,14 @@ public class BlockRegistries {
*/ */
public static final VersionedRegistry<BlockMappings> BLOCKS = VersionedRegistry.create(RegistryLoaders.empty(Int2ObjectOpenHashMap::new)); public static final VersionedRegistry<BlockMappings> BLOCKS = VersionedRegistry.create(RegistryLoaders.empty(Int2ObjectOpenHashMap::new));
/**
* A registry which stores Java IDs to Java {@link BlockState}s, each with their specific state differences and a link
* to the overarching block.
*/
public static final ListRegistry<BlockState> BLOCK_STATES = ListRegistry.create(RegistryLoaders.empty(ArrayList::new));
public static final ListRegistry<Block> JAVA_BLOCKS_TO_RENAME = ListRegistry.create(RegistryLoaders.empty(ArrayList::new));
/** /**
* A mapped registry which stores Java to Bedrock block identifiers. * A mapped registry which stores Java to Bedrock block identifiers.
*/ */
@ -72,19 +83,13 @@ public class BlockRegistries {
/** /**
* A mapped registry containing which holds block IDs to its {@link BlockCollision}. * A mapped registry containing which holds block IDs to its {@link BlockCollision}.
*/ */
public static final IntMappedRegistry<BlockCollision> COLLISIONS; public static final ListRegistry<BlockCollision> COLLISIONS;
/** /**
* A mapped registry containing the Java identifiers to IDs. * A mapped registry containing the Java identifiers to IDs.
*/ */
public static final MappedRegistry<String, Integer, Object2IntMap<String>> JAVA_IDENTIFIER_TO_ID = MappedRegistry.create(RegistryLoaders.empty(Object2IntOpenHashMap::new)); public static final MappedRegistry<String, Integer, Object2IntMap<String>> JAVA_IDENTIFIER_TO_ID = MappedRegistry.create(RegistryLoaders.empty(Object2IntOpenHashMap::new));
/**
* A registry which stores unique Java IDs to its clean identifier
* This is used in the statistics form.
*/
public static final ArrayRegistry<String> CLEAN_JAVA_IDENTIFIERS = ArrayRegistry.create(RegistryLoaders.uninitialized());
/** /**
* A registry containing all the waterlogged blockstates. * A registry containing all the waterlogged blockstates.
*/ */
@ -131,12 +136,13 @@ public class BlockRegistries {
public static final SimpleMappedRegistry<String, CustomSkull> CUSTOM_SKULLS = SimpleMappedRegistry.create(RegistryLoaders.empty(Object2ObjectOpenHashMap::new)); public static final SimpleMappedRegistry<String, CustomSkull> CUSTOM_SKULLS = SimpleMappedRegistry.create(RegistryLoaders.empty(Object2ObjectOpenHashMap::new));
static { static {
Blocks.VAULT.javaId(); // FIXME
CustomSkullRegistryPopulator.populate(); CustomSkullRegistryPopulator.populate();
BlockRegistryPopulator.populate(BlockRegistryPopulator.Stage.PRE_INIT); BlockRegistryPopulator.populate(BlockRegistryPopulator.Stage.PRE_INIT);
CustomBlockRegistryPopulator.populate(CustomBlockRegistryPopulator.Stage.DEFINITION); CustomBlockRegistryPopulator.populate(CustomBlockRegistryPopulator.Stage.DEFINITION);
CustomBlockRegistryPopulator.populate(CustomBlockRegistryPopulator.Stage.NON_VANILLA_REGISTRATION); CustomBlockRegistryPopulator.populate(CustomBlockRegistryPopulator.Stage.NON_VANILLA_REGISTRATION);
BlockRegistryPopulator.populate(BlockRegistryPopulator.Stage.INIT_JAVA); BlockRegistryPopulator.populate(BlockRegistryPopulator.Stage.INIT_JAVA);
COLLISIONS = IntMappedRegistry.create(Pair.of("org.geysermc.geyser.translator.collision.CollisionRemapper", "mappings/collision.json"), CollisionRegistryLoader::new); COLLISIONS = ListRegistry.create(Pair.of("org.geysermc.geyser.translator.collision.CollisionRemapper", "mappings/collisions.nbt"), CollisionRegistryLoader::new);
CustomBlockRegistryPopulator.populate(CustomBlockRegistryPopulator.Stage.VANILLA_REGISTRATION); CustomBlockRegistryPopulator.populate(CustomBlockRegistryPopulator.Stage.VANILLA_REGISTRATION);
CustomBlockRegistryPopulator.populate(CustomBlockRegistryPopulator.Stage.CUSTOM_REGISTRATION); CustomBlockRegistryPopulator.populate(CustomBlockRegistryPopulator.Stage.CUSTOM_REGISTRATION);
BlockRegistryPopulator.populate(BlockRegistryPopulator.Stage.INIT_BEDROCK); BlockRegistryPopulator.populate(BlockRegistryPopulator.Stage.INIT_BEDROCK);

Datei anzeigen

@ -0,0 +1,116 @@
/*
* 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;
import org.checkerframework.checker.nullness.qual.Nullable;
import org.geysermc.geyser.registry.loader.RegistryLoader;
import java.util.List;
import java.util.function.Supplier;
public class ListRegistry<M> extends Registry<List<M>> {
/**
* Creates a new instance of this class with the given input and
* {@link RegistryLoader}. The input specified is what the registry
* loader needs to take in.
*
* @param input the input
* @param registryLoader the registry loader
*/
protected <I> ListRegistry(I input, RegistryLoader<I, List<M>> registryLoader) {
super(input, registryLoader);
}
/**
* Returns the value registered by the given index.
*
* @param index the index
* @return the value registered by the given index.
*/
@Nullable
public M get(int index) {
if (index >= this.mappings.size()) {
return null;
}
return this.mappings.get(index);
}
/**
* Returns the value registered by the given index or the default value
* specified if null.
*
* @param index the index
* @param defaultValue the default value
* @return the value registered by the given key or the default value
* specified if null.
*/
public M getOrDefault(int index, M defaultValue) {
M value = this.get(index);
if (value == null) {
return defaultValue;
}
return value;
}
/**
* Registers a new value into this registry with the given index.
*
* @param index the index
* @param value the value
* @return a new value into this registry with the given index.
*/
public M register(int index, M value) {
return this.mappings.set(index, value);
}
/**
* Creates a new array registry with the given {@link RegistryLoader}. The
* input type is not specified here, meaning the loader return type is either
* predefined, or the registry is populated at a later point.
*
* @param registryLoader the registry loader
* @param <I> the input type
* @param <M> the returned mappings type
* @return a new registry with the given RegistryLoader supplier
*/
public static <I, M> ListRegistry<M> create(RegistryLoader<I, List<M>> registryLoader) {
return new ListRegistry<>(null, registryLoader);
}
/**
* Creates a new integer mapped registry with the given {@link RegistryLoader} and input.
*
* @param registryLoader the registry loader
* @param <I> the input
* @param <M> the type value
* @return a new registry with the given RegistryLoader supplier
*/
public static <I, M> ListRegistry<M> create(I input, Supplier<RegistryLoader<I, List<M>>> registryLoader) {
return new ListRegistry<>(input, registryLoader.get());
}
}

Datei anzeigen

@ -25,18 +25,19 @@
package org.geysermc.geyser.registry.loader; package org.geysermc.geyser.registry.loader;
import com.fasterxml.jackson.databind.node.ArrayNode;
import it.unimi.dsi.fastutil.Pair; 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.Object2ObjectOpenHashMap; import it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap;
import it.unimi.dsi.fastutil.objects.ObjectArrayList; import it.unimi.dsi.fastutil.objects.ObjectArrayList;
import lombok.AllArgsConstructor; import lombok.AllArgsConstructor;
import org.checkerframework.checker.nullness.qual.Nullable; import org.checkerframework.checker.nullness.qual.Nullable;
import org.cloudburstmc.nbt.NbtList;
import org.cloudburstmc.nbt.NbtMap;
import org.cloudburstmc.nbt.NbtType;
import org.cloudburstmc.nbt.NbtUtils;
import org.geysermc.geyser.GeyserImpl; import org.geysermc.geyser.GeyserImpl;
import org.geysermc.geyser.level.block.type.BlockState;
import org.geysermc.geyser.level.physics.BoundingBox; import org.geysermc.geyser.level.physics.BoundingBox;
import org.geysermc.geyser.registry.BlockRegistries; import org.geysermc.geyser.registry.BlockRegistries;
import org.geysermc.geyser.registry.type.BlockMapping;
import org.geysermc.geyser.translator.collision.BlockCollision; import org.geysermc.geyser.translator.collision.BlockCollision;
import org.geysermc.geyser.translator.collision.CollisionRemapper; import org.geysermc.geyser.translator.collision.CollisionRemapper;
import org.geysermc.geyser.translator.collision.OtherCollision; import org.geysermc.geyser.translator.collision.OtherCollision;
@ -51,41 +52,43 @@ import java.util.regex.Pattern;
/** /**
* Loads collision data from the given resource path. * Loads collision data from the given resource path.
*/ */
public class CollisionRegistryLoader extends MultiResourceRegistryLoader<String, Int2ObjectMap<BlockCollision>> { public class CollisionRegistryLoader extends MultiResourceRegistryLoader<String, List<BlockCollision>> {
@Override @Override
public Int2ObjectMap<BlockCollision> load(Pair<String, String> input) { public List<BlockCollision> load(Pair<String, String> input) {
Int2ObjectMap<BlockCollision> collisions = new Int2ObjectOpenHashMap<>();
Map<Class<?>, CollisionInfo> annotationMap = new IdentityHashMap<>(); Map<Class<?>, CollisionInfo> annotationMap = new IdentityHashMap<>();
for (Class<?> clazz : FileUtils.getGeneratedClassesForAnnotation(CollisionRemapper.class.getName())) { for (Class<?> clazz : FileUtils.getGeneratedClassesForAnnotation(CollisionRemapper.class.getName())) {
GeyserImpl.getInstance().getLogger().debug("Found annotated collision translator: " + clazz.getCanonicalName()); GeyserImpl.getInstance().getLogger().debug("Found annotated collision translator: " + clazz.getCanonicalName());
CollisionRemapper collisionRemapper = clazz.getAnnotation(CollisionRemapper.class); CollisionRemapper collisionRemapper = clazz.getAnnotation(CollisionRemapper.class);
annotationMap.put(clazz, new CollisionInfo(collisionRemapper, Pattern.compile(collisionRemapper.regex()), Pattern.compile(collisionRemapper.paramRegex()))); annotationMap.put(clazz, new CollisionInfo(collisionRemapper, Pattern.compile(collisionRemapper.regex())));
} }
// Load collision mappings file // Load collision mappings file
int[] indices;
List<BoundingBox[]> collisionList; List<BoundingBox[]> collisionList;
try (InputStream stream = GeyserImpl.getInstance().getBootstrap().getResourceOrThrow(input.value())) { try (InputStream stream = GeyserImpl.getInstance().getBootstrap().getResourceOrThrow(input.value())) {
ArrayNode collisionNode = (ArrayNode) GeyserImpl.JSON_MAPPER.readTree(stream); NbtMap collisionData = (NbtMap) NbtUtils.createGZIPReader(stream).readTag();
collisionList = loadBoundingBoxes(collisionNode); indices = collisionData.getIntArray("indices");
//SuppressWarnings unchecked
collisionList = loadBoundingBoxes(collisionData.getList("collisions", NbtType.LIST));
} catch (Exception e) { } catch (Exception e) {
throw new AssertionError("Unable to load collision data", e); throw new AssertionError("Unable to load collision data", e);
} }
BlockMapping[] blockMappings = BlockRegistries.JAVA_BLOCKS.get(); List<BlockState> blockStates = BlockRegistries.BLOCK_STATES.get();
List<BlockCollision> collisions = new ObjectArrayList<>(blockStates.size());
// Map of unique collisions to its instance // Map of unique collisions to its instance
Map<BlockCollision, BlockCollision> collisionInstances = new Object2ObjectOpenHashMap<>(); Map<BlockCollision, BlockCollision> collisionInstances = new Object2ObjectOpenHashMap<>();
for (int i = 0; i < blockMappings.length; i++) { for (int i = 0; i < blockStates.size(); i++) {
BlockMapping blockMapping = blockMappings[i]; BlockState state = blockStates.get(i);
if (blockMapping == null) { if (state == null) {
GeyserImpl.getInstance().getLogger().warning("Missing block mapping for Java block " + i); GeyserImpl.getInstance().getLogger().warning("Missing block state for Java block " + i);
continue; continue;
} }
BlockCollision newCollision = instantiateCollision(blockMapping, annotationMap, collisionList); BlockCollision newCollision = instantiateCollision(state, annotationMap, indices[i], collisionList);
if (newCollision != null) { if (newCollision != null) {
// If there's an existing instance equal to this one, use that instead // If there's an existing instance equal to this one, use that instead
@ -97,33 +100,27 @@ public class CollisionRegistryLoader extends MultiResourceRegistryLoader<String,
} }
} }
collisions.put(i, newCollision); collisions.add(newCollision);
} }
return collisions; return collisions;
} }
private @Nullable BlockCollision instantiateCollision(BlockMapping mapping, Map<Class<?>, CollisionInfo> annotationMap, List<BoundingBox[]> collisionList) { private @Nullable BlockCollision instantiateCollision(BlockState state, Map<Class<?>, CollisionInfo> annotationMap, int collisionIndex, List<BoundingBox[]> collisionList) {
String[] blockIdParts = mapping.getJavaIdentifier().split("\\["); String blockName = state.block().javaIdentifier().substring("minecraft:".length());
String blockName = blockIdParts[0].replace("minecraft:", "");
String params = "";
if (blockIdParts.length == 2) {
params = "[" + blockIdParts[1];
}
int collisionIndex = mapping.getCollisionIndex();
for (Map.Entry<Class<?>, CollisionInfo> collisionRemappers : annotationMap.entrySet()) { for (Map.Entry<Class<?>, CollisionInfo> collisionRemappers : annotationMap.entrySet()) {
Class<?> type = collisionRemappers.getKey(); Class<?> type = collisionRemappers.getKey();
CollisionInfo collisionInfo = collisionRemappers.getValue(); CollisionInfo collisionInfo = collisionRemappers.getValue();
CollisionRemapper annotation = collisionInfo.collisionRemapper; CollisionRemapper annotation = collisionInfo.collisionRemapper;
if (collisionInfo.pattern.matcher(blockName).find() && collisionInfo.paramsPattern.matcher(params).find()) { if (collisionInfo.pattern.matcher(blockName).find()) {
try { try {
if (annotation.passDefaultBoxes()) { if (annotation.passDefaultBoxes()) {
// Create an OtherCollision instance and get the bounding boxes // Create an OtherCollision instance and get the bounding boxes
BoundingBox[] defaultBoxes = collisionList.get(collisionIndex); BoundingBox[] defaultBoxes = collisionList.get(collisionIndex);
return (BlockCollision) type.getDeclaredConstructor(String.class, BoundingBox[].class).newInstance(params, defaultBoxes); return (BlockCollision) type.getDeclaredConstructor(BlockState.class, BoundingBox[].class).newInstance(state, defaultBoxes);
} else { } else {
return (BlockCollision) type.getDeclaredConstructor(String.class).newInstance(params); return (BlockCollision) type.getDeclaredConstructor(BlockState.class).newInstance(state);
} }
} catch (IllegalAccessException | InstantiationException | NoSuchMethodException | InvocationTargetException e) { } catch (IllegalAccessException | InstantiationException | NoSuchMethodException | InvocationTargetException e) {
throw new RuntimeException(e); throw new RuntimeException(e);
@ -138,25 +135,25 @@ public class CollisionRegistryLoader extends MultiResourceRegistryLoader<String,
// Unless some of the low IDs are changed, which is unlikely, the second item should always be full collision // Unless some of the low IDs are changed, which is unlikely, the second item should always be full collision
if (collisionIndex == 1) { if (collisionIndex == 1) {
return new SolidCollision(params); return new SolidCollision(state);
} }
return new OtherCollision(collisionList.get(collisionIndex)); return new OtherCollision(collisionList.get(collisionIndex));
} }
private List<BoundingBox[]> loadBoundingBoxes(ArrayNode collisionNode) { private List<BoundingBox[]> loadBoundingBoxes(List<NbtList> collisionNode) {
List<BoundingBox[]> collisions = new ObjectArrayList<>(); List<BoundingBox[]> collisions = new ObjectArrayList<>();
for (int collisionIndex = 0; collisionIndex < collisionNode.size(); collisionIndex++) { for (int collisionIndex = 0; collisionIndex < collisionNode.size(); collisionIndex++) {
ArrayNode boundingBoxArray = (ArrayNode) collisionNode.get(collisionIndex); @SuppressWarnings("unchecked") NbtList<NbtList<Double>> boundingBoxArray = (NbtList<NbtList<Double>>) collisionNode.get(collisionIndex);
BoundingBox[] boundingBoxes = new BoundingBox[boundingBoxArray.size()]; BoundingBox[] boundingBoxes = new BoundingBox[boundingBoxArray.size()];
for (int i = 0; i < boundingBoxArray.size(); i++) { for (int i = 0; i < boundingBoxArray.size(); i++) {
ArrayNode boxProperties = (ArrayNode) boundingBoxArray.get(i); NbtList<Double> boxProperties = boundingBoxArray.get(i);
boundingBoxes[i] = new BoundingBox(boxProperties.get(0).asDouble(), boundingBoxes[i] = new BoundingBox(boxProperties.get(0),
boxProperties.get(1).asDouble(), boxProperties.get(1),
boxProperties.get(2).asDouble(), boxProperties.get(2),
boxProperties.get(3).asDouble(), boxProperties.get(3),
boxProperties.get(4).asDouble(), boxProperties.get(4),
boxProperties.get(5).asDouble()); boxProperties.get(5));
} }
// Sorting by lowest Y first fixes some bugs // Sorting by lowest Y first fixes some bugs
@ -173,6 +170,5 @@ public class CollisionRegistryLoader extends MultiResourceRegistryLoader<String,
public static class CollisionInfo { public static class CollisionInfo {
private final CollisionRemapper collisionRemapper; private final CollisionRemapper collisionRemapper;
private final Pattern pattern; private final Pattern pattern;
private final Pattern paramsPattern;
} }
} }

Datei anzeigen

@ -51,6 +51,7 @@ import org.geysermc.geyser.api.block.custom.CustomBlockData;
import org.geysermc.geyser.api.block.custom.CustomBlockState; import org.geysermc.geyser.api.block.custom.CustomBlockState;
import org.geysermc.geyser.api.block.custom.nonvanilla.JavaBlockState; import org.geysermc.geyser.api.block.custom.nonvanilla.JavaBlockState;
import org.geysermc.geyser.level.block.BlockStateValues; import org.geysermc.geyser.level.block.BlockStateValues;
import org.geysermc.geyser.level.block.type.Block;
import org.geysermc.geyser.level.physics.PistonBehavior; import org.geysermc.geyser.level.physics.PistonBehavior;
import org.geysermc.geyser.registry.BlockRegistries; import org.geysermc.geyser.registry.BlockRegistries;
import org.geysermc.geyser.registry.type.BlockMapping; import org.geysermc.geyser.registry.type.BlockMapping;
@ -137,7 +138,7 @@ public final class BlockRegistryPopulator {
List<NbtMap> vanillaBlockStates; List<NbtMap> vanillaBlockStates;
List<NbtMap> blockStates; List<NbtMap> blockStates;
try (InputStream stream = GeyserImpl.getInstance().getBootstrap().getResourceOrThrow(String.format("bedrock/block_palette.%s.nbt", palette.key())); try (InputStream stream = GeyserImpl.getInstance().getBootstrap().getResourceOrThrow(String.format("bedrock/block_palette.%s.nbt", palette.key()));
NBTInputStream nbtInputStream = new NBTInputStream(new DataInputStream(new GZIPInputStream(stream)), true, true)) { NBTInputStream nbtInputStream = new NBTInputStream(new DataInputStream(new GZIPInputStream(stream)), true, true)) {
NbtMap blockPalette = (NbtMap) nbtInputStream.readTag(); NbtMap blockPalette = (NbtMap) nbtInputStream.readTag();
vanillaBlockStates = new ArrayList<>(blockPalette.getList("blocks", NbtType.COMPOUND)); vanillaBlockStates = new ArrayList<>(blockPalette.getList("blocks", NbtType.COMPOUND));
@ -259,7 +260,7 @@ public final class BlockRegistryPopulator {
bedrockDefinition = customBlockStateDefinitions.get(blockStateOverride); bedrockDefinition = customBlockStateDefinitions.get(blockStateOverride);
if (bedrockDefinition == null) { if (bedrockDefinition == null) {
throw new RuntimeException("Unable to find " + javaId + " Bedrock runtime ID! Custom block override: \n" + throw new RuntimeException("Unable to find " + javaId + " Bedrock runtime ID! Custom block override: \n" +
blockStateOverride); blockStateOverride);
} }
} }
@ -555,26 +556,6 @@ public final class BlockRegistryPopulator {
} }
BlockStateValues.JAVA_WATER_ID = waterRuntimeId; BlockStateValues.JAVA_WATER_ID = waterRuntimeId;
if (bubbleColumnDragRuntimeId == -1) {
throw new AssertionError("Unable to find drag bubble column in palette");
}
BlockStateValues.JAVA_BUBBLE_COLUMN_DRAG_ID = bubbleColumnDragRuntimeId;
if (bubbleColumnUpwardRuntimeId == -1) {
throw new AssertionError("Unable to find upward bubble column in palette");
}
BlockStateValues.JAVA_BUBBLE_COLUMN_UPWARD_ID = bubbleColumnUpwardRuntimeId;
if (soulSandRuntimeId == -1) {
throw new AssertionError("Unable to find soul sand in palette");
}
BlockStateValues.JAVA_SOUL_SAND_ID = soulSandRuntimeId;
if (iceRuntimeId == -1) {
throw new AssertionError("Unable to find ice in palette");
}
BlockStateValues.JAVA_ICE_ID = iceRuntimeId;
if (!BlockRegistries.NON_VANILLA_BLOCK_STATE_OVERRIDES.get().isEmpty()) { if (!BlockRegistries.NON_VANILLA_BLOCK_STATE_OVERRIDES.get().isEmpty()) {
Set<Integer> usedNonVanillaRuntimeIDs = new HashSet<>(); Set<Integer> usedNonVanillaRuntimeIDs = new HashSet<>();
@ -589,15 +570,24 @@ public final class BlockRegistryPopulator {
int stateRuntimeId = javaBlockState.javaId(); int stateRuntimeId = javaBlockState.javaId();
String pistonBehavior = javaBlockState.pistonBehavior(); String pistonBehavior = javaBlockState.pistonBehavior();
BlockMapping blockMapping = BlockMapping.builder() BlockMapping blockMapping = BlockMapping.builder()
.canBreakWithHand(javaBlockState.canBreakWithHand()) .canBreakWithHand(javaBlockState.canBreakWithHand())
.pickItem(javaBlockState.pickItem()) .pickItem(javaBlockState.pickItem())
.isNonVanilla(true) .isNonVanilla(true)
.javaIdentifier(javaId) .javaIdentifier(javaId)
.javaBlockId(javaBlockState.stateGroupId()) .javaBlockId(javaBlockState.stateGroupId())
.hardness(javaBlockState.blockHardness()) .hardness(javaBlockState.blockHardness())
.pistonBehavior(pistonBehavior == null ? PistonBehavior.NORMAL : PistonBehavior.getByName(pistonBehavior)) .pistonBehavior(pistonBehavior == null ? PistonBehavior.NORMAL : PistonBehavior.getByName(pistonBehavior))
.isBlockEntity(javaBlockState.hasBlockEntity()) .isBlockEntity(javaBlockState.hasBlockEntity())
.build(); .build();
Block.Builder builder = Block.builder()
.destroyTime(javaBlockState.blockHardness());
if (!javaBlockState.canBreakWithHand()) {
builder.requiresCorrectToolForDrops();
}
if (javaBlockState.hasBlockEntity()) {
builder.setBlockEntity();
}
String cleanJavaIdentifier = BlockUtils.getCleanIdentifier(javaBlockState.identifier()); String cleanJavaIdentifier = BlockUtils.getCleanIdentifier(javaBlockState.identifier());
String bedrockIdentifier = customBlockState.block().identifier(); String bedrockIdentifier = customBlockState.block().identifier();
@ -616,8 +606,6 @@ public final class BlockRegistryPopulator {
} }
} }
BlockRegistries.CLEAN_JAVA_IDENTIFIERS.set(cleanIdentifiers.toArray(new String[0]));
BLOCKS_JSON = blocksJson; BLOCKS_JSON = blocksJson;
JsonNode blockInteractionsJson; JsonNode blockInteractionsJson;

Datei anzeigen

@ -28,35 +28,6 @@ package org.geysermc.geyser.session;
import com.github.steveice10.mc.auth.data.GameProfile; import com.github.steveice10.mc.auth.data.GameProfile;
import com.github.steveice10.mc.auth.exception.request.RequestException; import com.github.steveice10.mc.auth.exception.request.RequestException;
import com.github.steveice10.mc.auth.service.MsaAuthenticationService; import com.github.steveice10.mc.auth.service.MsaAuthenticationService;
import org.geysermc.mcprotocollib.protocol.MinecraftConstants;
import org.geysermc.mcprotocollib.protocol.MinecraftProtocol;
import org.geysermc.mcprotocollib.protocol.data.ProtocolState;
import org.geysermc.mcprotocollib.protocol.data.UnexpectedEncryptionException;
import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.Pose;
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.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.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.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.player.ServerboundPlayerAbilitiesPacket;
import org.geysermc.mcprotocollib.protocol.packet.ingame.serverbound.player.ServerboundPlayerActionPacket;
import org.geysermc.mcprotocollib.protocol.packet.ingame.serverbound.player.ServerboundUseItemPacket;
import org.geysermc.mcprotocollib.protocol.packet.login.serverbound.ServerboundCustomQueryAnswerPacket;
import org.geysermc.mcprotocollib.network.BuiltinFlags;
import org.geysermc.mcprotocollib.network.Session;
import org.geysermc.mcprotocollib.network.event.session.*;
import org.geysermc.mcprotocollib.network.packet.Packet;
import org.geysermc.mcprotocollib.network.tcp.TcpClientSession;
import org.geysermc.mcprotocollib.network.tcp.TcpSession;
import io.netty.channel.Channel; import io.netty.channel.Channel;
import io.netty.channel.EventLoop; import io.netty.channel.EventLoop;
import it.unimi.dsi.fastutil.ints.Int2ObjectMap; import it.unimi.dsi.fastutil.ints.Int2ObjectMap;
@ -146,6 +117,38 @@ import org.geysermc.geyser.util.ChunkUtils;
import org.geysermc.geyser.util.DimensionUtils; import org.geysermc.geyser.util.DimensionUtils;
import org.geysermc.geyser.util.EntityUtils; import org.geysermc.geyser.util.EntityUtils;
import org.geysermc.geyser.util.LoginEncryptionUtils; import org.geysermc.geyser.util.LoginEncryptionUtils;
import org.geysermc.mcprotocollib.network.BuiltinFlags;
import org.geysermc.mcprotocollib.network.Session;
import org.geysermc.mcprotocollib.network.event.session.*;
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;
import org.geysermc.mcprotocollib.protocol.data.UnexpectedEncryptionException;
import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.Pose;
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.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.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.player.ServerboundPlayerAbilitiesPacket;
import org.geysermc.mcprotocollib.protocol.packet.ingame.serverbound.player.ServerboundPlayerActionPacket;
import org.geysermc.mcprotocollib.protocol.packet.ingame.serverbound.player.ServerboundUseItemPacket;
import org.geysermc.mcprotocollib.protocol.packet.login.serverbound.ServerboundCustomQueryAnswerPacket;
import java.net.ConnectException; import java.net.ConnectException;
import java.net.InetSocketAddress; import java.net.InetSocketAddress;
@ -660,9 +663,6 @@ public class GeyserSession implements GeyserConnection, GeyserCommandSource {
sentSpawnPacket = true; sentSpawnPacket = true;
syncEntityProperties(); syncEntityProperties();
// Set the hardcoded shield ID to the ID we just defined in StartGamePacket
// upstream.getSession().getHardcodedBlockingId().set(this.itemMappings.getStoredItems().shield().getBedrockId());
if (GeyserImpl.getInstance().getConfig().isAddNonBedrockItems()) { if (GeyserImpl.getInstance().getConfig().isAddNonBedrockItems()) {
ItemComponentPacket componentPacket = new ItemComponentPacket(); ItemComponentPacket componentPacket = new ItemComponentPacket();
componentPacket.getItems().addAll(itemMappings.getComponentItemData()); componentPacket.getItems().addAll(itemMappings.getComponentItemData());
@ -889,6 +889,8 @@ public class GeyserSession implements GeyserConnection, GeyserCommandSource {
// Start ticking // Start ticking
tickThread = eventLoop.scheduleAtFixedRate(this::tick, 50, 50, TimeUnit.MILLISECONDS); tickThread = eventLoop.scheduleAtFixedRate(this::tick, 50, 50, TimeUnit.MILLISECONDS);
this.protocol.setUseDefaultListeners(false);
TcpSession downstream; TcpSession downstream;
if (geyser.getBootstrap().getSocketAddress() != null) { if (geyser.getBootstrap().getSocketAddress() != null) {
// We're going to connect through the JVM and not through TCP // We're going to connect through the JVM and not through TCP
@ -918,6 +920,25 @@ public class GeyserSession implements GeyserConnection, GeyserCommandSource {
// Let Geyser handle sending the keep alive // Let Geyser handle sending the keep alive
downstream.setFlag(MinecraftConstants.AUTOMATIC_KEEP_ALIVE_MANAGEMENT, false); downstream.setFlag(MinecraftConstants.AUTOMATIC_KEEP_ALIVE_MANAGEMENT, false);
} }
// We'll handle this since we have the registry data on hand
downstream.setFlag(MinecraftConstants.SEND_BLANK_KNOWN_PACKS_RESPONSE, false);
// This isn't a great solution, but... we want to make sure the finish configuration packet cannot be sent
// before the KnownPacks packet.
this.downstream.getSession().addListener(new ClientListener(ProtocolState.LOGIN, loginEvent.transferring()) {
@Override
public void packetReceived(Session session, Packet packet) {
if (protocol.getState() == ProtocolState.CONFIGURATION) {
if (packet instanceof ClientboundFinishConfigurationPacket) {
// Prevent
GeyserSession.this.ensureInEventLoop(() -> GeyserSession.this.sendDownstreamPacket(new ServerboundFinishConfigurationPacket()));
return;
}
}
super.packetReceived(session, packet);
}
});
downstream.addListener(new SessionAdapter() { downstream.addListener(new SessionAdapter() {
@Override @Override
public void packetSending(PacketSendingEvent event) { public void packetSending(PacketSendingEvent event) {
@ -1564,8 +1585,7 @@ public class GeyserSession implements GeyserConnection, GeyserCommandSource {
startGamePacket.setEnchantmentSeed(0); startGamePacket.setEnchantmentSeed(0);
startGamePacket.setMultiplayerCorrelationId(""); startGamePacket.setMultiplayerCorrelationId("");
startGamePacket.setItemDefinitions(this.itemMappings.getItemDefinitions().values().stream().toList()); // TODO startGamePacket.getItemDefinitions().addAll(this.itemMappings.getItemDefinitions().values());
// startGamePacket.setBlockPalette(this.blockMappings.getBedrockBlockPalette());
// Needed for custom block mappings and custom skulls system // Needed for custom block mappings and custom skulls system
startGamePacket.getBlockProperties().addAll(this.blockMappings.getBlockProperties()); startGamePacket.getBlockProperties().addAll(this.blockMappings.getBlockProperties());
@ -1593,9 +1613,6 @@ public class GeyserSession implements GeyserConnection, GeyserCommandSource {
startGamePacket.setRewindHistorySize(0); startGamePacket.setRewindHistorySize(0);
startGamePacket.setServerAuthoritativeBlockBreaking(false); startGamePacket.setServerAuthoritativeBlockBreaking(false);
// Entity properties for older versions
startGamePacket.getExperiments().add(new ExperimentData("upcoming_creator_features", true));
upstream.sendPacket(startGamePacket); upstream.sendPacket(startGamePacket);
} }

Datei anzeigen

@ -25,6 +25,7 @@
package org.geysermc.geyser.session.cache; package org.geysermc.geyser.session.cache;
import org.geysermc.geyser.level.block.type.Block;
import org.geysermc.mcprotocollib.protocol.data.game.chunk.DataPalette; import org.geysermc.mcprotocollib.protocol.data.game.chunk.DataPalette;
import it.unimi.dsi.fastutil.longs.Long2ObjectMap; import it.unimi.dsi.fastutil.longs.Long2ObjectMap;
import it.unimi.dsi.fastutil.longs.Long2ObjectOpenHashMap; import it.unimi.dsi.fastutil.longs.Long2ObjectOpenHashMap;
@ -92,11 +93,11 @@ public class ChunkCache {
DataPalette palette = chunk.sections()[(y - minY) >> 4]; DataPalette palette = chunk.sections()[(y - minY) >> 4];
if (palette == null) { if (palette == null) {
if (block != BlockStateValues.JAVA_AIR_ID) { if (block != Block.JAVA_AIR_ID) {
// A previously empty chunk, which is no longer empty as a block has been added to it // A previously empty chunk, which is no longer empty as a block has been added to it
palette = DataPalette.createForChunk(); palette = DataPalette.createForChunk();
// Fixes the chunk assuming that all blocks is the `block` variable we are updating. /shrug // Fixes the chunk assuming that all blocks is the `block` variable we are updating. /shrug
palette.getPalette().stateToId(BlockStateValues.JAVA_AIR_ID); palette.getPalette().stateToId(Block.JAVA_AIR_ID);
chunk.sections()[(y - minY) >> 4] = palette; chunk.sections()[(y - minY) >> 4] = palette;
} else { } else {
// Nothing to update // Nothing to update
@ -109,17 +110,17 @@ public class ChunkCache {
public int getBlockAt(int x, int y, int z) { public int getBlockAt(int x, int y, int z) {
if (!cache) { if (!cache) {
return BlockStateValues.JAVA_AIR_ID; return Block.JAVA_AIR_ID;
} }
GeyserChunk column = this.getChunk(x >> 4, z >> 4); GeyserChunk column = this.getChunk(x >> 4, z >> 4);
if (column == null) { if (column == null) {
return BlockStateValues.JAVA_AIR_ID; return Block.JAVA_AIR_ID;
} }
if (y < minY || ((y - minY) >> 4) > column.sections().length - 1) { if (y < minY || ((y - minY) >> 4) > column.sections().length - 1) {
// Y likely goes above or below the height limit of this world // Y likely goes above or below the height limit of this world
return BlockStateValues.JAVA_AIR_ID; return Block.JAVA_AIR_ID;
} }
DataPalette chunk = column.sections()[(y - minY) >> 4]; DataPalette chunk = column.sections()[(y - minY) >> 4];
@ -127,7 +128,7 @@ public class ChunkCache {
return chunk.get(x & 0xF, y & 0xF, z & 0xF); return chunk.get(x & 0xF, y & 0xF, z & 0xF);
} }
return BlockStateValues.JAVA_AIR_ID; return Block.JAVA_AIR_ID;
} }
public void removeChunk(int chunkX, int chunkZ) { public void removeChunk(int chunkX, int chunkZ) {

Datei anzeigen

@ -30,6 +30,8 @@ import it.unimi.dsi.fastutil.ints.Int2IntOpenHashMap;
import lombok.AccessLevel; import lombok.AccessLevel;
import lombok.Getter; import lombok.Getter;
import lombok.experimental.Accessors; import lombok.experimental.Accessors;
import org.cloudburstmc.nbt.NbtMap;
import org.cloudburstmc.nbt.NbtType;
import org.cloudburstmc.protocol.bedrock.data.TrimMaterial; import org.cloudburstmc.protocol.bedrock.data.TrimMaterial;
import org.cloudburstmc.protocol.bedrock.data.TrimPattern; import org.cloudburstmc.protocol.bedrock.data.TrimPattern;
import org.geysermc.geyser.GeyserImpl; import org.geysermc.geyser.GeyserImpl;
@ -42,6 +44,7 @@ import org.geysermc.geyser.session.cache.registry.JavaRegistry;
import org.geysermc.geyser.session.cache.registry.SimpleJavaRegistry; import org.geysermc.geyser.session.cache.registry.SimpleJavaRegistry;
import org.geysermc.geyser.text.TextDecoration; import org.geysermc.geyser.text.TextDecoration;
import org.geysermc.geyser.translator.level.BiomeTranslator; import org.geysermc.geyser.translator.level.BiomeTranslator;
import org.geysermc.mcprotocollib.protocol.MinecraftProtocol;
import org.geysermc.mcprotocollib.protocol.data.game.RegistryEntry; import org.geysermc.mcprotocollib.protocol.data.game.RegistryEntry;
import org.geysermc.mcprotocollib.protocol.packet.configuration.clientbound.ClientboundRegistryDataPacket; import org.geysermc.mcprotocollib.protocol.packet.configuration.clientbound.ClientboundRegistryDataPacket;
@ -63,6 +66,7 @@ import java.util.function.ToIntFunction;
@Accessors(fluent = true) @Accessors(fluent = true)
@Getter @Getter
public final class RegistryCache { public final class RegistryCache {
private static final Map<String, Map<String, NbtMap>> DEFAULTS;
private static final Map<String, BiConsumer<RegistryCache, List<RegistryEntry>>> REGISTRIES = new HashMap<>(); private static final Map<String, BiConsumer<RegistryCache, List<RegistryEntry>>> REGISTRIES = new HashMap<>();
static { static {
@ -73,6 +77,24 @@ public final class RegistryCache {
register("worldgen/biome", (cache, array) -> cache.biomeTranslations = array, BiomeTranslator::loadServerBiome); register("worldgen/biome", (cache, array) -> cache.biomeTranslations = array, BiomeTranslator::loadServerBiome);
register("banner_pattern", cache -> cache.bannerPatterns, ($, entry) -> BannerPattern.getByJavaIdentifier(entry.getId())); register("banner_pattern", cache -> cache.bannerPatterns, ($, entry) -> BannerPattern.getByJavaIdentifier(entry.getId()));
register("wolf_variant", cache -> cache.wolfVariants, ($, entry) -> WolfEntity.WolfVariant.getByJavaIdentifier(entry.getId())); register("wolf_variant", cache -> cache.wolfVariants, ($, entry) -> WolfEntity.WolfVariant.getByJavaIdentifier(entry.getId()));
// Load from MCProtocolLib's classloader
NbtMap tag = MinecraftProtocol.loadNetworkCodec();
Map<String, Map<String, 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)
.getList("value", NbtType.COMPOUND);
Map<String, NbtMap> values = new HashMap<>();
for (NbtMap value : rawValues) {
String name = value.getString("name");
values.put(name, value.getCompound("element"));
}
// Can make these maps immutable and as efficient as possible after initialization
defaults.put(key, Map.copyOf(values));
});
DEFAULTS = Map.copyOf(defaults);
} }
@Getter(AccessLevel.NONE) @Getter(AccessLevel.NONE)
@ -116,13 +138,22 @@ public final class RegistryCache {
* @param <T> the class that represents these entries. * @param <T> the class that represents these entries.
*/ */
private static <T> void register(String registry, Function<RegistryCache, JavaRegistry<T>> localCacheFunction, BiFunction<GeyserSession, RegistryEntry, T> reader) { private static <T> void register(String registry, Function<RegistryCache, JavaRegistry<T>> localCacheFunction, BiFunction<GeyserSession, RegistryEntry, T> reader) {
REGISTRIES.put("minecraft:" + registry, (registryCache, entries) -> { String key = "minecraft:" + registry;
REGISTRIES.put(key, (registryCache, entries) -> {
Map<String, NbtMap> localRegistry = null;
JavaRegistry<T> localCache = localCacheFunction.apply(registryCache); JavaRegistry<T> localCache = localCacheFunction.apply(registryCache);
// Clear each local cache every time a new registry entry is given to us // Clear each local cache every time a new registry entry is given to us
// (e.g. proxy server switches) // (e.g. proxy server switches)
List<T> builder = new ArrayList<>(entries.size()); List<T> builder = new ArrayList<>(entries.size());
for (int i = 0; i < entries.size(); i++) { for (int i = 0; i < entries.size(); i++) {
RegistryEntry entry = entries.get(i); RegistryEntry entry = entries.get(i);
// 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(key);
}
entry = new RegistryEntry(entry.getId(), localRegistry.get(entry.getId()));
}
// This is what Geyser wants to keep as a value for this registry. // This is what Geyser wants to keep as a value for this registry.
T cacheEntry = reader.apply(registryCache.session, entry); T cacheEntry = reader.apply(registryCache.session, entry);
builder.add(i, cacheEntry); builder.add(i, cacheEntry);
@ -156,4 +187,8 @@ public final class RegistryCache {
localCacheFunction.accept(registryCache, array); localCacheFunction.accept(registryCache, array);
}); });
} }
public static void init() {
// no-op
}
} }

Datei anzeigen

@ -25,15 +25,16 @@
package org.geysermc.geyser.session.cache; package org.geysermc.geyser.session.cache;
import org.geysermc.mcprotocollib.protocol.packet.common.clientbound.ClientboundUpdateTagsPacket;
import it.unimi.dsi.fastutil.ints.IntList; import it.unimi.dsi.fastutil.ints.IntList;
import org.geysermc.geyser.GeyserLogger; import org.geysermc.geyser.GeyserLogger;
import org.geysermc.geyser.inventory.GeyserItemStack; import org.geysermc.geyser.inventory.GeyserItemStack;
import org.geysermc.geyser.item.type.Item; import org.geysermc.geyser.item.type.Item;
import org.geysermc.geyser.level.block.type.Block;
import org.geysermc.geyser.registry.type.BlockMapping; import org.geysermc.geyser.registry.type.BlockMapping;
import org.geysermc.geyser.session.GeyserSession; import org.geysermc.geyser.session.GeyserSession;
import org.geysermc.geyser.session.cache.tags.BlockTag; import org.geysermc.geyser.session.cache.tags.BlockTag;
import org.geysermc.geyser.session.cache.tags.ItemTag; import org.geysermc.geyser.session.cache.tags.ItemTag;
import org.geysermc.mcprotocollib.protocol.packet.common.clientbound.ClientboundUpdateTagsPacket;
import javax.annotation.ParametersAreNonnullByDefault; import javax.annotation.ParametersAreNonnullByDefault;
import java.util.EnumMap; import java.util.EnumMap;
@ -95,6 +96,17 @@ public final class TagCache {
} }
} }
/**
* @return true if the block tag is present and contains this block mapping's Java ID.
*/
public boolean is(BlockTag tag, Block block) {
IntList values = this.blocks.get(tag);
if (values != null) {
return values.contains(block.javaId());
}
return false;
}
/** /**
* @return true if the block tag is present and contains this block mapping's Java ID. * @return true if the block tag is present and contains this block mapping's Java ID.
*/ */

Datei anzeigen

@ -37,12 +37,6 @@ public @interface CollisionRemapper {
*/ */
String regex(); String regex();
/**
* Regex of block state parameters to apply this collision to
* Defaults to matching any value
*/
String paramRegex() default ".*";
/** /**
* Signals if a new instance needs to created for every block state * Signals if a new instance needs to created for every block state
*/ */

Datei anzeigen

@ -26,13 +26,14 @@
package org.geysermc.geyser.translator.collision; package org.geysermc.geyser.translator.collision;
import lombok.EqualsAndHashCode; import lombok.EqualsAndHashCode;
import org.geysermc.geyser.level.block.type.BlockState;
import org.geysermc.geyser.level.physics.BoundingBox; import org.geysermc.geyser.level.physics.BoundingBox;
import org.geysermc.geyser.level.physics.CollisionManager; import org.geysermc.geyser.level.physics.CollisionManager;
@EqualsAndHashCode(callSuper = true) @EqualsAndHashCode(callSuper = true)
@CollisionRemapper(regex = "^dirt_path$", passDefaultBoxes = true) @CollisionRemapper(regex = "^dirt_path$", passDefaultBoxes = true)
public class DirtPathCollision extends BlockCollision { public class DirtPathCollision extends BlockCollision {
public DirtPathCollision(String params, BoundingBox[] defaultBoxes) { public DirtPathCollision(BlockState state, BoundingBox[] defaultBoxes) {
super(defaultBoxes); super(defaultBoxes);
} }

Datei anzeigen

@ -26,6 +26,8 @@
package org.geysermc.geyser.translator.collision; package org.geysermc.geyser.translator.collision;
import lombok.EqualsAndHashCode; import lombok.EqualsAndHashCode;
import org.geysermc.geyser.level.block.property.Properties;
import org.geysermc.geyser.level.block.type.BlockState;
import org.geysermc.geyser.level.physics.BoundingBox; import org.geysermc.geyser.level.physics.BoundingBox;
import org.geysermc.geyser.session.GeyserSession; import org.geysermc.geyser.session.GeyserSession;
@ -40,20 +42,18 @@ public class DoorCollision extends BlockCollision {
*/ */
private int facing; private int facing;
public DoorCollision(String params, BoundingBox[] defaultBoxes) { public DoorCollision(BlockState state, BoundingBox[] defaultBoxes) {
super(defaultBoxes); super(defaultBoxes);
if (params.contains("facing=north")) { facing = switch (state.getValue(Properties.HORIZONTAL_FACING)) {
facing = 1; case NORTH -> 1;
} else if (params.contains("facing=east")) { case EAST -> 2;
facing = 2; case SOUTH -> 3;
} else if (params.contains("facing=south")) { case WEST -> 4;
facing = 3; default -> throw new IllegalStateException();
} else if (params.contains("facing=west")) { };
facing = 4;
}
// If the door is open it changes direction // If the door is open it changes direction
if (params.contains("open=true")) { if (state.getValue(Properties.OPEN)) {
facing = facing % 2 + 1; facing = facing % 2 + 1;
} }
} }

Datei anzeigen

@ -26,6 +26,8 @@
package org.geysermc.geyser.translator.collision; package org.geysermc.geyser.translator.collision;
import lombok.EqualsAndHashCode; import lombok.EqualsAndHashCode;
import org.geysermc.geyser.level.block.property.Properties;
import org.geysermc.geyser.level.block.type.BlockState;
import org.geysermc.geyser.level.physics.BoundingBox; import org.geysermc.geyser.level.physics.BoundingBox;
import org.geysermc.geyser.session.GeyserSession; import org.geysermc.geyser.session.GeyserSession;
@ -44,24 +46,23 @@ public class GlassPaneAndIronBarsCollision extends BlockCollision {
*/ */
private int facing; private int facing;
public GlassPaneAndIronBarsCollision(String params, BoundingBox[] defaultBoxes) { public GlassPaneAndIronBarsCollision(BlockState state, BoundingBox[] defaultBoxes) {
super(defaultBoxes); super(defaultBoxes);
//east=true,north=true,south=true,west=true if (state.getValue(Properties.NORTH) && state.getValue(Properties.EAST)) {
if (params.contains("north=true") && params.contains("east=true")) {
facing = 5; facing = 5;
} else if (params.contains("east=true") && params.contains("south=true")) { } else if (state.getValue(Properties.EAST) && state.getValue(Properties.SOUTH)) {
facing = 6; facing = 6;
} else if (params.contains("south=true") && params.contains("west=true")) { } else if (state.getValue(Properties.SOUTH) && state.getValue(Properties.WEST)) {
facing = 7; facing = 7;
} else if (params.contains("west=true") && params.contains("north=true")) { } else if (state.getValue(Properties.WEST) && state.getValue(Properties.NORTH)) {
facing = 8; facing = 8;
} else if (params.contains("north=true")) { } else if (state.getValue(Properties.NORTH)) {
facing = 1; facing = 1;
} else if (params.contains("east=true")) { } else if (state.getValue(Properties.EAST)) {
facing = 2; facing = 2;
} else if (params.contains("south=true")) { } else if (state.getValue(Properties.SOUTH)) {
facing = 3; facing = 3;
} else if (params.contains("west=true")) { } else if (state.getValue(Properties.WEST)) {
facing = 4; facing = 4;
} }
} }

Datei anzeigen

@ -26,6 +26,7 @@
package org.geysermc.geyser.translator.collision; package org.geysermc.geyser.translator.collision;
import lombok.EqualsAndHashCode; import lombok.EqualsAndHashCode;
import org.geysermc.geyser.level.block.type.BlockState;
import org.geysermc.geyser.level.physics.BoundingBox; import org.geysermc.geyser.level.physics.BoundingBox;
import org.geysermc.geyser.session.GeyserSession; import org.geysermc.geyser.session.GeyserSession;
@ -35,7 +36,7 @@ import org.geysermc.geyser.session.GeyserSession;
@EqualsAndHashCode(callSuper = true) @EqualsAndHashCode(callSuper = true)
@CollisionRemapper(regex = "^scaffolding$", usesParams = true, passDefaultBoxes = true) @CollisionRemapper(regex = "^scaffolding$", usesParams = true, passDefaultBoxes = true)
public class ScaffoldingCollision extends BlockCollision { public class ScaffoldingCollision extends BlockCollision {
public ScaffoldingCollision(String params, BoundingBox[] defaultBoxes) { public ScaffoldingCollision(BlockState state, BoundingBox[] defaultBoxes) {
super(defaultBoxes); super(defaultBoxes);
} }

Datei anzeigen

@ -30,7 +30,7 @@ import org.geysermc.geyser.level.physics.BoundingBox;
import org.geysermc.geyser.session.GeyserSession; import org.geysermc.geyser.session.GeyserSession;
@EqualsAndHashCode(callSuper = true) @EqualsAndHashCode(callSuper = true)
@CollisionRemapper(regex = "^snow$", passDefaultBoxes = true, usesParams = true) //@CollisionRemapper(regex = "^snow$", passDefaultBoxes = true, usesParams = true) TODO remove if no bugs are found. Seems fine with Bedrock 1.20.80 and 1.20.5
public class SnowCollision extends BlockCollision { public class SnowCollision extends BlockCollision {
private final int layers; private final int layers;

Datei anzeigen

@ -26,12 +26,13 @@
package org.geysermc.geyser.translator.collision; package org.geysermc.geyser.translator.collision;
import lombok.EqualsAndHashCode; import lombok.EqualsAndHashCode;
import org.geysermc.geyser.level.block.type.BlockState;
import org.geysermc.geyser.level.physics.BoundingBox; import org.geysermc.geyser.level.physics.BoundingBox;
@EqualsAndHashCode(callSuper = true) @EqualsAndHashCode(callSuper = true)
@CollisionRemapper(regex = "shulker_box$") // These have no collision in the mappings as it depends on the NBT data @CollisionRemapper(regex = "shulker_box$") // These have no collision in the mappings as it depends on the NBT data
public class SolidCollision extends BlockCollision { public class SolidCollision extends BlockCollision {
public SolidCollision(String params) { public SolidCollision(BlockState state) {
super(new BoundingBox[] { super(new BoundingBox[] {
new BoundingBox(0.5, 0.5, 0.5, 1, 1, 1) new BoundingBox(0.5, 0.5, 0.5, 1, 1, 1)
}); });

Datei anzeigen

@ -26,42 +26,27 @@
package org.geysermc.geyser.translator.collision; package org.geysermc.geyser.translator.collision;
import lombok.EqualsAndHashCode; import lombok.EqualsAndHashCode;
import org.geysermc.geyser.level.block.property.Properties;
import org.geysermc.geyser.level.block.type.BlockState;
import org.geysermc.geyser.level.physics.BoundingBox; import org.geysermc.geyser.level.physics.BoundingBox;
import org.geysermc.geyser.level.physics.CollisionManager; import org.geysermc.geyser.level.physics.CollisionManager;
import org.geysermc.geyser.level.physics.Direction;
import org.geysermc.geyser.session.GeyserSession; import org.geysermc.geyser.session.GeyserSession;
@EqualsAndHashCode(callSuper = true) @EqualsAndHashCode(callSuper = true)
@CollisionRemapper(regex = "_trapdoor$", usesParams = true, passDefaultBoxes = true) @CollisionRemapper(regex = "_trapdoor$", usesParams = true, passDefaultBoxes = true)
public class TrapdoorCollision extends BlockCollision { public class TrapdoorCollision extends BlockCollision {
/** private final Direction facing;
* 1 = north
* 2 = east
* 3 = south
* 4 = west
* 5 = up
* 6 = down
*/
private int facing;
public TrapdoorCollision(String params, BoundingBox[] defaultBoxes) { public TrapdoorCollision(BlockState state, BoundingBox[] defaultBoxes) {
super(defaultBoxes); super(defaultBoxes);
if (params.contains("open=true")) { if (state.getValue(Properties.OPEN)) {
if (params.contains("facing=north")) { facing = state.getValue(Properties.HORIZONTAL_FACING);
facing = 1;
} else if (params.contains("facing=east")) {
facing = 2;
} else if (params.contains("facing=south")) {
facing = 3;
} else if (params.contains("facing=west")) {
facing = 4;
}
} else { } else {
if (params.contains("half=bottom")) { if (state.getValue(Properties.HALF).equals("bottom")) {
// Up facing = Direction.UP;
facing = 5;
} else { } else {
// Down facing = Direction.DOWN;
facing = 6;
} }
} }
} }
@ -72,22 +57,22 @@ public class TrapdoorCollision extends BlockCollision {
// Check for door bug (doors are 0.1875 blocks thick on Java but 0.1825 blocks thick on Bedrock) // Check for door bug (doors are 0.1875 blocks thick on Java but 0.1825 blocks thick on Bedrock)
if (this.checkIntersection(x, y, z, playerCollision)) { if (this.checkIntersection(x, y, z, playerCollision)) {
switch (facing) { switch (facing) {
case 1: // North case NORTH:
playerCollision.setMiddleZ(z + 0.5125); playerCollision.setMiddleZ(z + 0.5125);
break; break;
case 2: // East case EAST:
playerCollision.setMiddleX(x + 0.5125); playerCollision.setMiddleX(x + 0.5125);
break; break;
case 3: // South case SOUTH:
playerCollision.setMiddleZ(z + 0.4875); playerCollision.setMiddleZ(z + 0.4875);
break; break;
case 4: // West case WEST:
playerCollision.setMiddleX(x + 0.4875); playerCollision.setMiddleX(x + 0.4875);
break; break;
case 5: case UP:
// Up-facing trapdoors are handled by the step-up check // Up-facing trapdoors are handled by the step-up check
break; break;
case 6: // Down case DOWN:
// (top y of trap door) - (trap door thickness) = top y of player // (top y of trap door) - (trap door thickness) = top y of player
playerCollision.setMiddleY(y + 1 - (3.0 / 16.0) - playerCollision.getSizeY() / 2.0 - CollisionManager.COLLISION_TOLERANCE); playerCollision.setMiddleY(y + 1 - (3.0 / 16.0) - playerCollision.getSizeY() / 2.0 - CollisionManager.COLLISION_TOLERANCE);
break; break;

Datei anzeigen

@ -35,6 +35,7 @@ import org.geysermc.geyser.inventory.BedrockContainerSlot;
import org.geysermc.geyser.inventory.Inventory; import org.geysermc.geyser.inventory.Inventory;
import org.geysermc.geyser.inventory.holder.BlockInventoryHolder; import org.geysermc.geyser.inventory.holder.BlockInventoryHolder;
import org.geysermc.geyser.inventory.updater.ContainerInventoryUpdater; import org.geysermc.geyser.inventory.updater.ContainerInventoryUpdater;
import org.geysermc.geyser.level.block.type.BlockState;
import org.geysermc.geyser.registry.Registries; import org.geysermc.geyser.registry.Registries;
import org.geysermc.geyser.session.GeyserSession; import org.geysermc.geyser.session.GeyserSession;
import org.geysermc.geyser.translator.level.block.entity.BlockEntityTranslator; import org.geysermc.geyser.translator.level.block.entity.BlockEntityTranslator;
@ -58,7 +59,7 @@ public class ShulkerInventoryTranslator extends AbstractBlockInventoryTranslator
.putInt("z", position.getZ()) .putInt("z", position.getZ())
.putString("CustomName", inventory.getTitle()); .putString("CustomName", inventory.getTitle());
// Don't reset facing property // Don't reset facing property
shulkerBoxTranslator.translateTag(session, tag, null, javaBlockState); shulkerBoxTranslator.translateTag(session, tag, null, BlockState.of(javaBlockState));
BlockEntityDataPacket dataPacket = new BlockEntityDataPacket(); BlockEntityDataPacket dataPacket = new BlockEntityDataPacket();
dataPacket.setData(tag.build()); dataPacket.setData(tag.build());

Datei anzeigen

@ -36,8 +36,7 @@ import org.cloudburstmc.protocol.bedrock.packet.ContainerOpenPacket;
import org.cloudburstmc.protocol.bedrock.packet.UpdateBlockPacket; import org.cloudburstmc.protocol.bedrock.packet.UpdateBlockPacket;
import org.geysermc.geyser.inventory.Container; import org.geysermc.geyser.inventory.Container;
import org.geysermc.geyser.inventory.Inventory; import org.geysermc.geyser.inventory.Inventory;
import org.geysermc.geyser.level.block.BlockStateValues; import org.geysermc.geyser.level.block.type.BlockState;
import org.geysermc.geyser.level.block.DoubleChestValue;
import org.geysermc.geyser.registry.BlockRegistries; import org.geysermc.geyser.registry.BlockRegistries;
import org.geysermc.geyser.registry.type.BlockMapping; import org.geysermc.geyser.registry.type.BlockMapping;
import org.geysermc.geyser.session.GeyserSession; import org.geysermc.geyser.session.GeyserSession;
@ -72,8 +71,8 @@ public class DoubleChestInventoryTranslator extends ChestInventoryTranslator {
.putString("CustomName", inventory.getTitle()) .putString("CustomName", inventory.getTitle())
.putString("id", "Chest"); .putString("id", "Chest");
DoubleChestValue chestValue = BlockStateValues.getDoubleChestValues().get(javaBlockId); BlockState blockState = BlockState.of(javaBlockId);
DoubleChestBlockEntityTranslator.translateChestValue(tag, chestValue, DoubleChestBlockEntityTranslator.translateChestValue(tag, blockState,
session.getLastInteractionBlockPosition().getX(), session.getLastInteractionBlockPosition().getZ()); session.getLastInteractionBlockPosition().getX(), session.getLastInteractionBlockPosition().getZ());
BlockEntityDataPacket dataPacket = new BlockEntityDataPacket(); BlockEntityDataPacket dataPacket = new BlockEntityDataPacket();

Datei anzeigen

@ -30,7 +30,8 @@ import org.cloudburstmc.nbt.NbtMap;
import org.cloudburstmc.nbt.NbtMapBuilder; import org.cloudburstmc.nbt.NbtMapBuilder;
import org.cloudburstmc.nbt.NbtType; import org.cloudburstmc.nbt.NbtType;
import org.geysermc.geyser.item.type.BannerItem; import org.geysermc.geyser.item.type.BannerItem;
import org.geysermc.geyser.level.block.BlockStateValues; import org.geysermc.geyser.level.block.type.BannerBlock;
import org.geysermc.geyser.level.block.type.BlockState;
import org.geysermc.geyser.session.GeyserSession; import org.geysermc.geyser.session.GeyserSession;
import org.geysermc.mcprotocollib.protocol.data.game.level.block.BlockEntityType; import org.geysermc.mcprotocollib.protocol.data.game.level.block.BlockEntityType;
@ -39,10 +40,9 @@ import java.util.List;
@BlockEntity(type = BlockEntityType.BANNER) @BlockEntity(type = BlockEntityType.BANNER)
public class BannerBlockEntityTranslator extends BlockEntityTranslator implements RequiresBlockState { public class BannerBlockEntityTranslator extends BlockEntityTranslator implements RequiresBlockState {
@Override @Override
public void translateTag(GeyserSession session, NbtMapBuilder bedrockNbt, @Nullable NbtMap javaNbt, int blockState) { public void translateTag(GeyserSession session, NbtMapBuilder bedrockNbt, @Nullable NbtMap javaNbt, BlockState blockState) {
int bannerColor = BlockStateValues.getBannerColor(blockState); if (blockState.block() instanceof BannerBlock banner) {
if (bannerColor != -1) { bedrockNbt.putInt("Base", 15 - banner.dyeColor());
bedrockNbt.putInt("Base", 15 - bannerColor);
} }
if (javaNbt == null) { if (javaNbt == null) {

Datei anzeigen

@ -27,13 +27,14 @@ package org.geysermc.geyser.translator.level.block.entity;
import org.cloudburstmc.nbt.NbtMap; import org.cloudburstmc.nbt.NbtMap;
import org.cloudburstmc.nbt.NbtMapBuilder; import org.cloudburstmc.nbt.NbtMapBuilder;
import org.geysermc.geyser.level.block.type.BlockState;
import org.geysermc.geyser.session.GeyserSession; import org.geysermc.geyser.session.GeyserSession;
import org.geysermc.mcprotocollib.protocol.data.game.level.block.BlockEntityType; import org.geysermc.mcprotocollib.protocol.data.game.level.block.BlockEntityType;
@BlockEntity(type = BlockEntityType.BEACON) @BlockEntity(type = BlockEntityType.BEACON)
public class BeaconBlockEntityTranslator extends BlockEntityTranslator { public class BeaconBlockEntityTranslator extends BlockEntityTranslator {
@Override @Override
public void translateTag(GeyserSession session, NbtMapBuilder bedrockNbt, NbtMap javaNbt, int blockState) { public void translateTag(GeyserSession session, NbtMapBuilder bedrockNbt, NbtMap javaNbt, BlockState blockState) {
int primary = javaNbt.getInt("primary"); int primary = javaNbt.getInt("primary");
// The effects here generally map one-to-one Java <-> Bedrock. Only the newer ones get more complicated // The effects here generally map one-to-one Java <-> Bedrock. Only the newer ones get more complicated
bedrockNbt.putInt("primary", primary == -1 ? 0 : primary); bedrockNbt.putInt("primary", primary == -1 ? 0 : primary);

Datei anzeigen

@ -27,19 +27,15 @@ package org.geysermc.geyser.translator.level.block.entity;
import org.cloudburstmc.nbt.NbtMap; import org.cloudburstmc.nbt.NbtMap;
import org.cloudburstmc.nbt.NbtMapBuilder; import org.cloudburstmc.nbt.NbtMapBuilder;
import org.geysermc.geyser.level.block.BlockStateValues; import org.geysermc.geyser.level.block.type.BedBlock;
import org.geysermc.geyser.level.block.type.BlockState;
import org.geysermc.geyser.session.GeyserSession; import org.geysermc.geyser.session.GeyserSession;
import org.geysermc.mcprotocollib.protocol.data.game.level.block.BlockEntityType; import org.geysermc.mcprotocollib.protocol.data.game.level.block.BlockEntityType;
@BlockEntity(type = BlockEntityType.BED) @BlockEntity(type = BlockEntityType.BED)
public class BedBlockEntityTranslator extends BlockEntityTranslator implements RequiresBlockState { public class BedBlockEntityTranslator extends BlockEntityTranslator implements RequiresBlockState {
@Override @Override
public void translateTag(GeyserSession session, NbtMapBuilder bedrockNbt, NbtMap javaNbt, int blockState) { public void translateTag(GeyserSession session, NbtMapBuilder bedrockNbt, NbtMap javaNbt, BlockState blockState) {
byte bedcolor = BlockStateValues.getBedColor(blockState); bedrockNbt.putByte("color", (byte) (blockState.block() instanceof BedBlock bed ? bed.dyeColor() : 0));
// Just in case...
if (bedcolor == -1) {
bedcolor = 0;
}
bedrockNbt.putByte("color", bedcolor);
} }
} }

Datei anzeigen

@ -31,6 +31,7 @@ import org.cloudburstmc.nbt.NbtList;
import org.cloudburstmc.nbt.NbtMap; import org.cloudburstmc.nbt.NbtMap;
import org.cloudburstmc.nbt.NbtType; import org.cloudburstmc.nbt.NbtType;
import org.geysermc.geyser.level.block.BlockStateValues; import org.geysermc.geyser.level.block.BlockStateValues;
import org.geysermc.geyser.level.block.type.BlockState;
import org.geysermc.geyser.session.GeyserSession; import org.geysermc.geyser.session.GeyserSession;
/** /**
@ -50,7 +51,7 @@ public interface BedrockOnlyBlockEntity extends RequiresBlockState {
* @param blockState The Java block state. * @param blockState The Java block state.
* @param position The Bedrock block position. * @param position The Bedrock block position.
*/ */
void updateBlock(GeyserSession session, int blockState, Vector3i position); void updateBlock(GeyserSession session, BlockState blockState, Vector3i position);
/** /**
* Get the tag of the Bedrock-only block entity * Get the tag of the Bedrock-only block entity

Datei anzeigen

@ -28,6 +28,7 @@ package org.geysermc.geyser.translator.level.block.entity;
import org.checkerframework.checker.nullness.qual.Nullable; import org.checkerframework.checker.nullness.qual.Nullable;
import org.cloudburstmc.nbt.NbtMap; import org.cloudburstmc.nbt.NbtMap;
import org.cloudburstmc.nbt.NbtMapBuilder; import org.cloudburstmc.nbt.NbtMapBuilder;
import org.geysermc.geyser.level.block.type.BlockState;
import org.geysermc.geyser.session.GeyserSession; import org.geysermc.geyser.session.GeyserSession;
import org.geysermc.geyser.util.BlockEntityUtils; import org.geysermc.geyser.util.BlockEntityUtils;
import org.geysermc.mcprotocollib.protocol.data.game.level.block.BlockEntityType; import org.geysermc.mcprotocollib.protocol.data.game.level.block.BlockEntityType;
@ -39,9 +40,9 @@ public abstract class BlockEntityTranslator {
protected BlockEntityTranslator() { protected BlockEntityTranslator() {
} }
public abstract void translateTag(GeyserSession session, NbtMapBuilder bedrockNbt, NbtMap javaNbt, int blockState); public abstract void translateTag(GeyserSession session, NbtMapBuilder bedrockNbt, NbtMap javaNbt, BlockState blockState);
public NbtMap getBlockEntityTag(GeyserSession session, BlockEntityType type, int x, int y, int z, @Nullable NbtMap javaNbt, int blockState) { public NbtMap getBlockEntityTag(GeyserSession session, BlockEntityType type, int x, int y, int z, @Nullable NbtMap javaNbt, BlockState blockState) {
NbtMapBuilder tagBuilder = getConstantBedrockTag(type, x, y, z); NbtMapBuilder tagBuilder = getConstantBedrockTag(type, x, y, z);
if (javaNbt != null || this instanceof RequiresBlockState) { if (javaNbt != null || this instanceof RequiresBlockState) {
// Always process tags if the block state is part of the tag. // Always process tags if the block state is part of the tag.

Datei anzeigen

@ -29,7 +29,8 @@ import org.checkerframework.checker.nullness.qual.Nullable;
import org.cloudburstmc.nbt.NbtMap; import org.cloudburstmc.nbt.NbtMap;
import org.cloudburstmc.nbt.NbtMapBuilder; import org.cloudburstmc.nbt.NbtMapBuilder;
import org.geysermc.geyser.item.Items; import org.geysermc.geyser.item.Items;
import org.geysermc.geyser.level.block.BlockStateValues; import org.geysermc.geyser.level.block.property.Properties;
import org.geysermc.geyser.level.block.type.BlockState;
import org.geysermc.geyser.registry.type.ItemMapping; import org.geysermc.geyser.registry.type.ItemMapping;
import org.geysermc.geyser.session.GeyserSession; import org.geysermc.geyser.session.GeyserSession;
import org.geysermc.mcprotocollib.protocol.data.game.level.block.BlockEntityType; import org.geysermc.mcprotocollib.protocol.data.game.level.block.BlockEntityType;
@ -38,7 +39,7 @@ import org.geysermc.mcprotocollib.protocol.data.game.level.block.BlockEntityType
public class BrushableBlockEntityTranslator extends BlockEntityTranslator implements RequiresBlockState { public class BrushableBlockEntityTranslator extends BlockEntityTranslator implements RequiresBlockState {
@Override @Override
public void translateTag(GeyserSession session, NbtMapBuilder bedrockNbt, @Nullable NbtMap javaNbt, int blockState) { public void translateTag(GeyserSession session, NbtMapBuilder bedrockNbt, @Nullable NbtMap javaNbt, BlockState blockState) {
if (javaNbt == null) { if (javaNbt == null) {
return; return;
} }
@ -70,6 +71,6 @@ public class BrushableBlockEntityTranslator extends BlockEntityTranslator implem
// controls which side the item protrudes from // controls which side the item protrudes from
bedrockNbt.putByte("brush_direction", hitDirection); bedrockNbt.putByte("brush_direction", hitDirection);
// controls how much the item protrudes // controls how much the item protrudes
bedrockNbt.putInt("brush_count", BlockStateValues.getBrushProgress(blockState)); bedrockNbt.putInt("brush_count", blockState.getValue(Properties.DUSTED));
} }
} }

Datei anzeigen

@ -28,6 +28,7 @@ package org.geysermc.geyser.translator.level.block.entity;
import org.cloudburstmc.nbt.NbtMap; import org.cloudburstmc.nbt.NbtMap;
import org.cloudburstmc.nbt.NbtMapBuilder; import org.cloudburstmc.nbt.NbtMapBuilder;
import org.cloudburstmc.nbt.NbtType; import org.cloudburstmc.nbt.NbtType;
import org.geysermc.geyser.level.block.type.BlockState;
import org.geysermc.geyser.registry.type.ItemMapping; import org.geysermc.geyser.registry.type.ItemMapping;
import org.geysermc.geyser.session.GeyserSession; import org.geysermc.geyser.session.GeyserSession;
import org.geysermc.geyser.translator.item.BedrockItemBuilder; import org.geysermc.geyser.translator.item.BedrockItemBuilder;
@ -38,7 +39,7 @@ import java.util.List;
@BlockEntity(type = BlockEntityType.CAMPFIRE) @BlockEntity(type = BlockEntityType.CAMPFIRE)
public class CampfireBlockEntityTranslator extends BlockEntityTranslator { public class CampfireBlockEntityTranslator extends BlockEntityTranslator {
@Override @Override
public void translateTag(GeyserSession session, NbtMapBuilder bedrockNbt, NbtMap javaNbt, int blockState) { public void translateTag(GeyserSession session, NbtMapBuilder bedrockNbt, NbtMap javaNbt, BlockState blockState) {
List<NbtMap> items = javaNbt.getList("Items", NbtType.COMPOUND); List<NbtMap> items = javaNbt.getList("Items", NbtType.COMPOUND);
if (items != null) { if (items != null) {
int i = 1; int i = 1;

Datei anzeigen

@ -27,7 +27,8 @@ package org.geysermc.geyser.translator.level.block.entity;
import org.cloudburstmc.nbt.NbtMap; import org.cloudburstmc.nbt.NbtMap;
import org.cloudburstmc.nbt.NbtMapBuilder; import org.cloudburstmc.nbt.NbtMapBuilder;
import org.geysermc.geyser.level.block.BlockStateValues; import org.geysermc.geyser.level.block.property.Properties;
import org.geysermc.geyser.level.block.type.BlockState;
import org.geysermc.geyser.session.GeyserSession; import org.geysermc.geyser.session.GeyserSession;
import org.geysermc.geyser.translator.text.MessageTranslator; import org.geysermc.geyser.translator.text.MessageTranslator;
import org.geysermc.mcprotocollib.protocol.data.game.level.block.BlockEntityType; import org.geysermc.mcprotocollib.protocol.data.game.level.block.BlockEntityType;
@ -35,12 +36,12 @@ import org.geysermc.mcprotocollib.protocol.data.game.level.block.BlockEntityType
@BlockEntity(type = BlockEntityType.COMMAND_BLOCK) @BlockEntity(type = BlockEntityType.COMMAND_BLOCK)
public class CommandBlockBlockEntityTranslator extends BlockEntityTranslator implements RequiresBlockState { public class CommandBlockBlockEntityTranslator extends BlockEntityTranslator implements RequiresBlockState {
@Override @Override
public void translateTag(GeyserSession session, NbtMapBuilder bedrockNbt, NbtMap javaNbt, int blockState) { public void translateTag(GeyserSession session, NbtMapBuilder bedrockNbt, NbtMap javaNbt, BlockState blockState) {
if (javaNbt == null || javaNbt.size() < 5) { if (javaNbt == null || javaNbt.size() < 5) {
return; // These values aren't here return; // These values aren't here
} }
// Java infers from the block state, but Bedrock needs it in the tag // Java infers from the block state, but Bedrock needs it in the tag
bedrockNbt.putByte("conditionalMode", BlockStateValues.getCommandBlockValues().getOrDefault(blockState, (byte) 0)); bedrockNbt.putBoolean("conditionalMode", blockState.getValue(Properties.CONDITIONAL));
// Java and Bedrock values // Java and Bedrock values
bedrockNbt.putByte("conditionMet", javaNbt.getByte("conditionMet")); bedrockNbt.putByte("conditionMet", javaNbt.getByte("conditionMet"));
bedrockNbt.putByte("auto", javaNbt.getByte("auto")); bedrockNbt.putByte("auto", javaNbt.getByte("auto"));

Datei anzeigen

@ -28,6 +28,7 @@ package org.geysermc.geyser.translator.level.block.entity;
import org.cloudburstmc.nbt.NbtMap; import org.cloudburstmc.nbt.NbtMap;
import org.cloudburstmc.nbt.NbtMapBuilder; import org.cloudburstmc.nbt.NbtMapBuilder;
import org.cloudburstmc.nbt.NbtType; import org.cloudburstmc.nbt.NbtType;
import org.geysermc.geyser.level.block.type.BlockState;
import org.geysermc.geyser.session.GeyserSession; import org.geysermc.geyser.session.GeyserSession;
import org.geysermc.mcprotocollib.protocol.data.game.level.block.BlockEntityType; import org.geysermc.mcprotocollib.protocol.data.game.level.block.BlockEntityType;
@ -35,7 +36,7 @@ import org.geysermc.mcprotocollib.protocol.data.game.level.block.BlockEntityType
public class DecoratedPotBlockEntityTranslator extends BlockEntityTranslator { public class DecoratedPotBlockEntityTranslator extends BlockEntityTranslator {
@Override @Override
public void translateTag(GeyserSession session, NbtMapBuilder bedrockNbt, NbtMap javaNbt, int blockState) { public void translateTag(GeyserSession session, NbtMapBuilder bedrockNbt, NbtMap javaNbt, BlockState blockState) {
if (javaNbt == null) { if (javaNbt == null) {
return; return;
} }

Datei anzeigen

@ -29,7 +29,9 @@ import org.cloudburstmc.math.vector.Vector3i;
import org.cloudburstmc.nbt.NbtMap; import org.cloudburstmc.nbt.NbtMap;
import org.cloudburstmc.nbt.NbtMapBuilder; import org.cloudburstmc.nbt.NbtMapBuilder;
import org.geysermc.geyser.level.block.BlockStateValues; import org.geysermc.geyser.level.block.BlockStateValues;
import org.geysermc.geyser.level.block.DoubleChestValue; import org.geysermc.geyser.level.block.property.Properties;
import org.geysermc.geyser.level.block.type.BlockState;
import org.geysermc.geyser.level.physics.Direction;
import org.geysermc.geyser.session.GeyserSession; import org.geysermc.geyser.session.GeyserSession;
import org.geysermc.geyser.util.BlockEntityUtils; import org.geysermc.geyser.util.BlockEntityUtils;
import org.geysermc.mcprotocollib.protocol.data.game.level.block.BlockEntityType; import org.geysermc.mcprotocollib.protocol.data.game.level.block.BlockEntityType;
@ -45,52 +47,40 @@ public class DoubleChestBlockEntityTranslator extends BlockEntityTranslator impl
} }
@Override @Override
public void updateBlock(GeyserSession session, int blockState, Vector3i position) { public void updateBlock(GeyserSession session, BlockState blockState, Vector3i position) {
NbtMapBuilder tagBuilder = getConstantBedrockTag(BlockEntityUtils.getBedrockBlockEntityId(BlockEntityType.CHEST), position.getX(), position.getY(), position.getZ()); NbtMapBuilder tagBuilder = getConstantBedrockTag(BlockEntityUtils.getBedrockBlockEntityId(BlockEntityType.CHEST), position.getX(), position.getY(), position.getZ());
translateTag(session, tagBuilder, null, blockState); translateTag(session, tagBuilder, null, blockState);
BlockEntityUtils.updateBlockEntity(session, tagBuilder.build(), position); BlockEntityUtils.updateBlockEntity(session, tagBuilder.build(), position);
} }
@Override @Override
public void translateTag(GeyserSession session, NbtMapBuilder bedrockNbt, NbtMap javaNbt, int blockState) { public void translateTag(GeyserSession session, NbtMapBuilder bedrockNbt, NbtMap javaNbt, BlockState blockState) {
DoubleChestValue chestValues = BlockStateValues.getDoubleChestValues().get(blockState); int x = (int) bedrockNbt.get("x");
if (chestValues != null) { int z = (int) bedrockNbt.get("z");
int x = (int) bedrockNbt.get("x"); translateChestValue(bedrockNbt, blockState, x, z);
int z = (int) bedrockNbt.get("z");
translateChestValue(bedrockNbt, chestValues, x, z);
}
} }
/** /**
* Add Bedrock block entity tags to a NbtMap based on Java properties * Add Bedrock block entity tags to a NbtMap based on Java properties
* *
* @param builder the NbtMapBuilder to apply properties to * @param builder the NbtMapBuilder to apply properties to
* @param chestValues the position properties of this double chest * @param state the BlockState of this double chest
* @param x the x position of this chest pair * @param x the x position of this chest pair
* @param z the z position of this chest pair * @param z the z position of this chest pair
*/ */
public static void translateChestValue(NbtMapBuilder builder, DoubleChestValue chestValues, int x, int z) { public static void translateChestValue(NbtMapBuilder builder, BlockState state, int x, int z) {
// Calculate the position of the other chest based on the Java block state // Calculate the position of the other chest based on the Java block state
if (chestValues.isFacingEast()) { Direction facing = state.getValue(Properties.HORIZONTAL_FACING);
if (chestValues.isDirectionPositive()) { boolean isLeft = state.getValue(Properties.CHEST_TYPE).equals("left"); //TODO enum
// East switch (facing) {
z = z + (chestValues.isLeft() ? 1 : -1); case EAST -> z = z + (isLeft ? 1 : -1);
} else { case WEST -> z = z + (isLeft ? -1 : 1);
// West case SOUTH -> x = x + (isLeft ? -1 : 1);
z = z + (chestValues.isLeft() ? -1 : 1); case NORTH -> x = x + (isLeft ? 1 : -1);
}
} else {
if (chestValues.isDirectionPositive()) {
// South
x = x + (chestValues.isLeft() ? -1 : 1);
} else {
// North
x = x + (chestValues.isLeft() ? 1 : -1);
}
} }
builder.putInt("pairx", x); builder.putInt("pairx", x);
builder.putInt("pairz", z); builder.putInt("pairz", z);
if (!chestValues.isLeft()) { if (!isLeft) {
builder.putInt("pairlead", (byte) 1); builder.putInt("pairlead", (byte) 1);
} }
} }

Datei anzeigen

@ -27,10 +27,11 @@ package org.geysermc.geyser.translator.level.block.entity;
import org.cloudburstmc.nbt.NbtMap; import org.cloudburstmc.nbt.NbtMap;
import org.cloudburstmc.nbt.NbtMapBuilder; import org.cloudburstmc.nbt.NbtMapBuilder;
import org.geysermc.geyser.level.block.type.BlockState;
import org.geysermc.geyser.session.GeyserSession; import org.geysermc.geyser.session.GeyserSession;
public class EmptyBlockEntityTranslator extends BlockEntityTranslator { public class EmptyBlockEntityTranslator extends BlockEntityTranslator {
@Override @Override
public void translateTag(GeyserSession session, NbtMapBuilder bedrockNbt, NbtMap javaNbt, int blockState) { public void translateTag(GeyserSession session, NbtMapBuilder bedrockNbt, NbtMap javaNbt, BlockState blockState) {
} }
} }

Datei anzeigen

@ -31,13 +31,14 @@ import org.cloudburstmc.nbt.NbtList;
import org.cloudburstmc.nbt.NbtMap; import org.cloudburstmc.nbt.NbtMap;
import org.cloudburstmc.nbt.NbtMapBuilder; import org.cloudburstmc.nbt.NbtMapBuilder;
import org.cloudburstmc.nbt.NbtType; import org.cloudburstmc.nbt.NbtType;
import org.geysermc.geyser.level.block.type.BlockState;
import org.geysermc.geyser.session.GeyserSession; import org.geysermc.geyser.session.GeyserSession;
import org.geysermc.mcprotocollib.protocol.data.game.level.block.BlockEntityType; import org.geysermc.mcprotocollib.protocol.data.game.level.block.BlockEntityType;
@BlockEntity(type = BlockEntityType.END_GATEWAY) @BlockEntity(type = BlockEntityType.END_GATEWAY)
public class EndGatewayBlockEntityTranslator extends BlockEntityTranslator { public class EndGatewayBlockEntityTranslator extends BlockEntityTranslator {
@Override @Override
public void translateTag(GeyserSession session, NbtMapBuilder bedrockNbt, NbtMap javaNbt, int blockState) { public void translateTag(GeyserSession session, NbtMapBuilder bedrockNbt, NbtMap javaNbt, BlockState blockState) {
bedrockNbt.putInt("Age", (int) javaNbt.getLong("Age")); bedrockNbt.putInt("Age", (int) javaNbt.getLong("Age"));
// Java sometimes does not provide this tag, but Bedrock crashes if it doesn't exist // Java sometimes does not provide this tag, but Bedrock crashes if it doesn't exist
// Linked coordinates // Linked coordinates

Datei anzeigen

@ -30,6 +30,7 @@ import org.cloudburstmc.nbt.NbtMap;
import org.cloudburstmc.nbt.NbtMapBuilder; import org.cloudburstmc.nbt.NbtMapBuilder;
import org.cloudburstmc.protocol.bedrock.packet.UpdateBlockPacket; import org.cloudburstmc.protocol.bedrock.packet.UpdateBlockPacket;
import org.geysermc.geyser.level.block.BlockStateValues; import org.geysermc.geyser.level.block.BlockStateValues;
import org.geysermc.geyser.level.block.type.BlockState;
import org.geysermc.geyser.session.GeyserSession; import org.geysermc.geyser.session.GeyserSession;
import org.geysermc.geyser.util.BlockEntityUtils; import org.geysermc.geyser.util.BlockEntityUtils;
@ -75,12 +76,12 @@ public class FlowerPotBlockEntityTranslator implements BedrockOnlyBlockEntity {
} }
@Override @Override
public void updateBlock(GeyserSession session, int blockState, Vector3i position) { public void updateBlock(GeyserSession session, BlockState blockState, Vector3i position) {
NbtMap tag = getTag(session, blockState, position); NbtMap tag = getTag(session, blockState.javaId(), position);
BlockEntityUtils.updateBlockEntity(session, tag, position); BlockEntityUtils.updateBlockEntity(session, tag, position);
UpdateBlockPacket updateBlockPacket = new UpdateBlockPacket(); UpdateBlockPacket updateBlockPacket = new UpdateBlockPacket();
updateBlockPacket.setDataLayer(0); updateBlockPacket.setDataLayer(0);
updateBlockPacket.setDefinition(session.getBlockMappings().getBedrockBlock(blockState)); updateBlockPacket.setDefinition(session.getBlockMappings().getBedrockBlock(blockState.javaId()));
updateBlockPacket.setBlockPosition(position); updateBlockPacket.setBlockPosition(position);
updateBlockPacket.getFlags().add(UpdateBlockPacket.Flag.NEIGHBORS); updateBlockPacket.getFlags().add(UpdateBlockPacket.Flag.NEIGHBORS);
updateBlockPacket.getFlags().add(UpdateBlockPacket.Flag.NETWORK); updateBlockPacket.getFlags().add(UpdateBlockPacket.Flag.NETWORK);

Datei anzeigen

@ -29,13 +29,14 @@ import org.checkerframework.checker.nullness.qual.Nullable;
import org.cloudburstmc.nbt.NbtMap; import org.cloudburstmc.nbt.NbtMap;
import org.cloudburstmc.nbt.NbtMapBuilder; import org.cloudburstmc.nbt.NbtMapBuilder;
import org.geysermc.geyser.level.block.BlockStateValues; import org.geysermc.geyser.level.block.BlockStateValues;
import org.geysermc.geyser.level.block.type.BlockState;
import org.geysermc.geyser.session.GeyserSession; import org.geysermc.geyser.session.GeyserSession;
import org.geysermc.mcprotocollib.protocol.data.game.level.block.BlockEntityType; import org.geysermc.mcprotocollib.protocol.data.game.level.block.BlockEntityType;
@BlockEntity(type = BlockEntityType.JIGSAW) @BlockEntity(type = BlockEntityType.JIGSAW)
public class JigsawBlockBlockEntityTranslator extends BlockEntityTranslator implements RequiresBlockState { public class JigsawBlockBlockEntityTranslator extends BlockEntityTranslator implements RequiresBlockState {
@Override @Override
public void translateTag(GeyserSession session, NbtMapBuilder bedrockNbt, @Nullable NbtMap javaNbt, int blockState) { public void translateTag(GeyserSession session, NbtMapBuilder bedrockNbt, @Nullable NbtMap javaNbt, BlockState blockState) {
if (javaNbt == null) { if (javaNbt == null) {
return; return;
} }
@ -46,7 +47,7 @@ public class JigsawBlockBlockEntityTranslator extends BlockEntityTranslator impl
} else { } else {
// Tag is not present in at least 1.14.4 Paper // Tag is not present in at least 1.14.4 Paper
// Minecraft 1.18.1 deliberately has a fallback here, but not for any other value // Minecraft 1.18.1 deliberately has a fallback here, but not for any other value
bedrockNbt.putString("joint", BlockStateValues.getHorizontalFacingJigsaws().contains(blockState) ? "aligned" : "rollable"); bedrockNbt.putString("joint", BlockStateValues.getHorizontalFacingJigsaws().contains(blockState.javaId()) ? "aligned" : "rollable"); // TODO
} }
bedrockNbt.putString("name", javaNbt.getString("name")); bedrockNbt.putString("name", javaNbt.getString("name"));
bedrockNbt.putString("target_pool", javaNbt.getString("target_pool")); bedrockNbt.putString("target_pool", javaNbt.getString("target_pool"));

Datei anzeigen

@ -25,6 +25,7 @@
package org.geysermc.geyser.translator.level.block.entity; package org.geysermc.geyser.translator.level.block.entity;
import org.geysermc.geyser.level.block.type.Block;
import org.geysermc.mcprotocollib.protocol.data.game.level.block.value.PistonValueType; import org.geysermc.mcprotocollib.protocol.data.game.level.block.value.PistonValueType;
import org.cloudburstmc.math.vector.Vector3d; import org.cloudburstmc.math.vector.Vector3d;
import org.cloudburstmc.math.vector.Vector3f; import org.cloudburstmc.math.vector.Vector3f;
@ -222,10 +223,10 @@ public class PistonBlockEntity {
Vector3i blockInFront = position.add(orientation.getUnitVector()); Vector3i blockInFront = position.add(orientation.getUnitVector());
int blockId = session.getGeyser().getWorldManager().getBlockAt(session, blockInFront); int blockId = session.getGeyser().getWorldManager().getBlockAt(session, blockInFront);
if (BlockStateValues.isPistonHead(blockId)) { if (BlockStateValues.isPistonHead(blockId)) {
ChunkUtils.updateBlock(session, BlockStateValues.JAVA_AIR_ID, blockInFront); ChunkUtils.updateBlock(session, Block.JAVA_AIR_ID, blockInFront);
} else if ((session.getGeyser().getPlatformType() == PlatformType.SPIGOT || session.getErosionHandler().isActive()) && blockId == BlockStateValues.JAVA_AIR_ID) { } else if ((session.getGeyser().getPlatformType() == PlatformType.SPIGOT || session.getErosionHandler().isActive()) && blockId == Block.JAVA_AIR_ID) {
// Spigot removes the piston head from the cache, but we need to send the block update ourselves // Spigot removes the piston head from the cache, but we need to send the block update ourselves
ChunkUtils.updateBlock(session, BlockStateValues.JAVA_AIR_ID, blockInFront); ChunkUtils.updateBlock(session, Block.JAVA_AIR_ID, blockInFront);
} }
} }
@ -255,7 +256,7 @@ public class PistonBlockEntity {
continue; continue;
} }
int blockId = session.getGeyser().getWorldManager().getBlockAt(session, blockPos); int blockId = session.getGeyser().getWorldManager().getBlockAt(session, blockPos);
if (blockId == BlockStateValues.JAVA_AIR_ID) { if (blockId == Block.JAVA_AIR_ID) {
continue; continue;
} }
if (BlockStateValues.canPistonMoveBlock(blockId, action == PistonValueType.PUSHING)) { if (BlockStateValues.canPistonMoveBlock(blockId, action == PistonValueType.PUSHING)) {
@ -278,7 +279,7 @@ public class PistonBlockEntity {
continue; continue;
} }
int adjacentBlockId = session.getGeyser().getWorldManager().getBlockAt(session, adjacentPos); int adjacentBlockId = session.getGeyser().getWorldManager().getBlockAt(session, adjacentPos);
if (adjacentBlockId != BlockStateValues.JAVA_AIR_ID && BlockStateValues.isBlockAttached(blockId, adjacentBlockId) && BlockStateValues.canPistonMoveBlock(adjacentBlockId, false)) { if (adjacentBlockId != Block.JAVA_AIR_ID && BlockStateValues.isBlockAttached(blockId, adjacentBlockId) && BlockStateValues.canPistonMoveBlock(adjacentBlockId, false)) {
// If it is another slime/honey block we need to check its adjacent blocks // If it is another slime/honey block we need to check its adjacent blocks
if (BlockStateValues.isBlockSticky(adjacentBlockId)) { if (BlockStateValues.isBlockSticky(adjacentBlockId)) {
blocksToCheck.add(adjacentPos); blocksToCheck.add(adjacentPos);
@ -322,7 +323,7 @@ public class PistonBlockEntity {
*/ */
private void removeBlocks() { private void removeBlocks() {
for (Vector3i blockPos : attachedBlocks.keySet()) { for (Vector3i blockPos : attachedBlocks.keySet()) {
ChunkUtils.updateBlock(session, BlockStateValues.JAVA_AIR_ID, blockPos); ChunkUtils.updateBlock(session, Block.JAVA_AIR_ID, blockPos);
} }
if (action != PistonValueType.PUSHING) { if (action != PistonValueType.PUSHING) {
removePistonHead(); removePistonHead();
@ -560,7 +561,7 @@ public class PistonBlockEntity {
if (blockPos.equals(getPistonHeadPos())) { if (blockPos.equals(getPistonHeadPos())) {
return BlockStateValues.getPistonHead(orientation); return BlockStateValues.getPistonHead(orientation);
} else { } else {
return attachedBlocks.getOrDefault(blockPos, BlockStateValues.JAVA_AIR_ID); return attachedBlocks.getOrDefault(blockPos, Block.JAVA_AIR_ID);
} }
} }

Datei anzeigen

@ -28,7 +28,8 @@ package org.geysermc.geyser.translator.level.block.entity;
import org.checkerframework.checker.nullness.qual.Nullable; import org.checkerframework.checker.nullness.qual.Nullable;
import org.cloudburstmc.nbt.NbtMap; import org.cloudburstmc.nbt.NbtMap;
import org.cloudburstmc.nbt.NbtMapBuilder; import org.cloudburstmc.nbt.NbtMapBuilder;
import org.geysermc.geyser.level.block.BlockStateValues; import org.geysermc.geyser.level.block.property.Properties;
import org.geysermc.geyser.level.block.type.BlockState;
import org.geysermc.geyser.session.GeyserSession; import org.geysermc.geyser.session.GeyserSession;
import org.geysermc.geyser.translator.inventory.ShulkerInventoryTranslator; import org.geysermc.geyser.translator.inventory.ShulkerInventoryTranslator;
import org.geysermc.mcprotocollib.protocol.data.game.level.block.BlockEntityType; import org.geysermc.mcprotocollib.protocol.data.game.level.block.BlockEntityType;
@ -40,12 +41,7 @@ public class ShulkerBoxBlockEntityTranslator extends BlockEntityTranslator imple
* where {@code tag} is passed as null. * where {@code tag} is passed as null.
*/ */
@Override @Override
public void translateTag(GeyserSession session, NbtMapBuilder bedrockNbt, @Nullable NbtMap javaNbt, int blockState) { public void translateTag(GeyserSession session, NbtMapBuilder bedrockNbt, @Nullable NbtMap javaNbt, BlockState blockState) {
byte direction = BlockStateValues.getShulkerBoxDirection(blockState); bedrockNbt.putByte("facing", (byte) blockState.getValue(Properties.FACING).ordinal());
// Just in case...
if (direction == -1) {
direction = 1;
}
bedrockNbt.putByte("facing", direction);
} }
} }

Datei anzeigen

@ -28,6 +28,7 @@ package org.geysermc.geyser.translator.level.block.entity;
import org.cloudburstmc.nbt.NbtMap; import org.cloudburstmc.nbt.NbtMap;
import org.cloudburstmc.nbt.NbtMapBuilder; import org.cloudburstmc.nbt.NbtMapBuilder;
import org.cloudburstmc.nbt.NbtType; import org.cloudburstmc.nbt.NbtType;
import org.geysermc.geyser.level.block.type.BlockState;
import org.geysermc.geyser.session.GeyserSession; import org.geysermc.geyser.session.GeyserSession;
import org.geysermc.geyser.text.ChatColor; import org.geysermc.geyser.text.ChatColor;
import org.geysermc.geyser.translator.text.MessageTranslator; import org.geysermc.geyser.translator.text.MessageTranslator;
@ -73,7 +74,7 @@ public class SignBlockEntityTranslator extends BlockEntityTranslator {
} }
@Override @Override
public void translateTag(GeyserSession session, NbtMapBuilder bedrockNbt, NbtMap javaNbt, int blockState) { public void translateTag(GeyserSession session, NbtMapBuilder bedrockNbt, NbtMap javaNbt, BlockState blockState) {
bedrockNbt.putCompound("FrontText", translateSide(javaNbt.getCompound("front_text"))); bedrockNbt.putCompound("FrontText", translateSide(javaNbt.getCompound("front_text")));
bedrockNbt.putCompound("BackText", translateSide(javaNbt.getCompound("back_text"))); bedrockNbt.putCompound("BackText", translateSide(javaNbt.getCompound("back_text")));
bedrockNbt.putBoolean("IsWaxed", javaNbt.getBoolean("is_waxed")); bedrockNbt.putBoolean("IsWaxed", javaNbt.getBoolean("is_waxed"));

Datei anzeigen

@ -34,6 +34,8 @@ import org.cloudburstmc.protocol.bedrock.data.definitions.BlockDefinition;
import org.cloudburstmc.protocol.bedrock.packet.UpdateBlockPacket; import org.cloudburstmc.protocol.bedrock.packet.UpdateBlockPacket;
import org.geysermc.geyser.GeyserImpl; import org.geysermc.geyser.GeyserImpl;
import org.geysermc.geyser.level.block.BlockStateValues; import org.geysermc.geyser.level.block.BlockStateValues;
import org.geysermc.geyser.level.block.property.Properties;
import org.geysermc.geyser.level.block.type.BlockState;
import org.geysermc.geyser.session.GeyserSession; import org.geysermc.geyser.session.GeyserSession;
import org.geysermc.geyser.session.cache.SkullCache; import org.geysermc.geyser.session.cache.SkullCache;
import org.geysermc.geyser.skin.SkinProvider; import org.geysermc.geyser.skin.SkinProvider;
@ -50,16 +52,19 @@ import java.util.concurrent.ExecutionException;
public class SkullBlockEntityTranslator extends BlockEntityTranslator implements RequiresBlockState { public class SkullBlockEntityTranslator extends BlockEntityTranslator implements RequiresBlockState {
@Override @Override
public void translateTag(GeyserSession session, NbtMapBuilder bedrockNbt, NbtMap javaNbt, int blockState) { public void translateTag(GeyserSession session, NbtMapBuilder bedrockNbt, NbtMap javaNbt, BlockState blockState) {
byte skullVariant = BlockStateValues.getSkullVariant(blockState); byte skullVariant = BlockStateValues.getSkullVariant(blockState.javaId()); // TODO
float rotation = BlockStateValues.getSkullRotation(blockState) * 22.5f;
// Just in case... // Just in case...
if (skullVariant == -1) { if (skullVariant == -1) {
skullVariant = 0; skullVariant = 0;
} }
bedrockNbt.putFloat("Rotation", rotation); Integer rotation = blockState.getValue(Properties.ROTATION_16);
if (rotation != null) {
// Could be a wall skull block
bedrockNbt.putFloat("Rotation", rotation * 22.5f);
}
bedrockNbt.putByte("SkullType", skullVariant); bedrockNbt.putByte("SkullType", skullVariant);
if (BlockStateValues.isSkullPowered(blockState)) { if (blockState.getValue(Properties.POWERED)) {
bedrockNbt.putBoolean("MouthMoving", true); bedrockNbt.putBoolean("MouthMoving", true);
} }
} }

Datei anzeigen

@ -32,6 +32,7 @@ import org.cloudburstmc.nbt.NbtMap;
import org.cloudburstmc.nbt.NbtMapBuilder; import org.cloudburstmc.nbt.NbtMapBuilder;
import org.cloudburstmc.protocol.bedrock.packet.UpdateBlockPacket; import org.cloudburstmc.protocol.bedrock.packet.UpdateBlockPacket;
import org.geysermc.geyser.entity.EntityDefinition; import org.geysermc.geyser.entity.EntityDefinition;
import org.geysermc.geyser.level.block.type.BlockState;
import org.geysermc.geyser.registry.Registries; import org.geysermc.geyser.registry.Registries;
import org.geysermc.geyser.session.GeyserSession; import org.geysermc.geyser.session.GeyserSession;
import org.geysermc.mcprotocollib.protocol.data.game.level.block.BlockEntityType; import org.geysermc.mcprotocollib.protocol.data.game.level.block.BlockEntityType;
@ -40,7 +41,7 @@ import org.geysermc.mcprotocollib.protocol.data.game.level.block.BlockEntityType
public class SpawnerBlockEntityTranslator extends BlockEntityTranslator { public class SpawnerBlockEntityTranslator extends BlockEntityTranslator {
@Override @Override
public NbtMap getBlockEntityTag(GeyserSession session, BlockEntityType type, int x, int y, int z, @Nullable NbtMap javaNbt, int blockState) { public NbtMap getBlockEntityTag(GeyserSession session, BlockEntityType type, int x, int y, int z, @Nullable NbtMap javaNbt, BlockState blockState) {
if (javaNbt == null) { if (javaNbt == null) {
return super.getBlockEntityTag(session, type, x, y, z, javaNbt, blockState); return super.getBlockEntityTag(session, type, x, y, z, javaNbt, blockState);
} }
@ -70,7 +71,7 @@ public class SpawnerBlockEntityTranslator extends BlockEntityTranslator {
} }
@Override @Override
public void translateTag(GeyserSession session, NbtMapBuilder bedrockNbt, NbtMap javaNbt, int blockState) { public void translateTag(GeyserSession session, NbtMapBuilder bedrockNbt, NbtMap javaNbt, BlockState blockState) {
Object current; Object current;
// TODO use primitive get and put methods // TODO use primitive get and put methods

Datei anzeigen

@ -32,6 +32,7 @@ import org.cloudburstmc.nbt.NbtMapBuilder;
import org.cloudburstmc.protocol.bedrock.data.structure.StructureMirror; import org.cloudburstmc.protocol.bedrock.data.structure.StructureMirror;
import org.cloudburstmc.protocol.bedrock.data.structure.StructureRotation; import org.cloudburstmc.protocol.bedrock.data.structure.StructureRotation;
import org.cloudburstmc.protocol.bedrock.packet.UpdateBlockPacket; import org.cloudburstmc.protocol.bedrock.packet.UpdateBlockPacket;
import org.geysermc.geyser.level.block.type.BlockState;
import org.geysermc.geyser.session.GeyserSession; import org.geysermc.geyser.session.GeyserSession;
import org.geysermc.geyser.util.StructureBlockUtils; import org.geysermc.geyser.util.StructureBlockUtils;
import org.geysermc.mcprotocollib.protocol.data.game.level.block.BlockEntityType; import org.geysermc.mcprotocollib.protocol.data.game.level.block.BlockEntityType;
@ -40,7 +41,7 @@ import org.geysermc.mcprotocollib.protocol.data.game.level.block.BlockEntityType
public class StructureBlockBlockEntityTranslator extends BlockEntityTranslator { public class StructureBlockBlockEntityTranslator extends BlockEntityTranslator {
@Override @Override
public NbtMap getBlockEntityTag(GeyserSession session, BlockEntityType type, int x, int y, int z, @Nullable NbtMap javaNbt, int blockState) { public NbtMap getBlockEntityTag(GeyserSession session, BlockEntityType type, int x, int y, int z, @Nullable NbtMap javaNbt, BlockState blockState) {
if (javaNbt == null) { if (javaNbt == null) {
return super.getBlockEntityTag(session, type, x, y, z, javaNbt, blockState); return super.getBlockEntityTag(session, type, x, y, z, javaNbt, blockState);
} }
@ -73,7 +74,7 @@ public class StructureBlockBlockEntityTranslator extends BlockEntityTranslator {
} }
@Override @Override
public void translateTag(GeyserSession session, NbtMapBuilder bedrockNbt, NbtMap javaNbt, int blockState) { public void translateTag(GeyserSession session, NbtMapBuilder bedrockNbt, NbtMap javaNbt, BlockState blockState) {
if (javaNbt.size() < 5) { if (javaNbt.size() < 5) {
return; // These values aren't here return; // These values aren't here
} }

Datei anzeigen

@ -27,6 +27,7 @@ package org.geysermc.geyser.translator.level.block.entity;
import org.cloudburstmc.nbt.NbtMap; import org.cloudburstmc.nbt.NbtMap;
import org.cloudburstmc.nbt.NbtMapBuilder; import org.cloudburstmc.nbt.NbtMapBuilder;
import org.geysermc.geyser.level.block.type.BlockState;
import org.geysermc.geyser.session.GeyserSession; import org.geysermc.geyser.session.GeyserSession;
import org.geysermc.mcprotocollib.protocol.data.game.level.block.BlockEntityType; import org.geysermc.mcprotocollib.protocol.data.game.level.block.BlockEntityType;
@ -34,7 +35,7 @@ import org.geysermc.mcprotocollib.protocol.data.game.level.block.BlockEntityType
public class TrialSpawnerBlockEntityTranslator extends BlockEntityTranslator { public class TrialSpawnerBlockEntityTranslator extends BlockEntityTranslator {
@Override @Override
public void translateTag(GeyserSession session, NbtMapBuilder bedrockNbt, NbtMap javaNbt, int blockState) { public void translateTag(GeyserSession session, NbtMapBuilder bedrockNbt, NbtMap javaNbt, BlockState blockState) {
if (javaNbt == null) { if (javaNbt == null) {
return; return;
} }

Datei anzeigen

@ -25,6 +25,7 @@
package org.geysermc.geyser.translator.protocol.bedrock; package org.geysermc.geyser.translator.protocol.bedrock;
import org.geysermc.geyser.level.block.type.Block;
import org.geysermc.mcprotocollib.protocol.data.game.item.ItemStack; import org.geysermc.mcprotocollib.protocol.data.game.item.ItemStack;
import org.cloudburstmc.math.vector.Vector3i; import org.cloudburstmc.math.vector.Vector3i;
import org.cloudburstmc.protocol.bedrock.packet.BlockPickRequestPacket; import org.cloudburstmc.protocol.bedrock.packet.BlockPickRequestPacket;
@ -48,7 +49,7 @@ public class BedrockBlockPickRequestTranslator extends PacketTranslator<BlockPic
int blockToPick = session.getGeyser().getWorldManager().getBlockAt(session, vector.getX(), vector.getY(), vector.getZ()); int blockToPick = session.getGeyser().getWorldManager().getBlockAt(session, vector.getX(), vector.getY(), vector.getZ());
// Block is air - chunk caching is probably off // Block is air - chunk caching is probably off
if (blockToPick == BlockStateValues.JAVA_AIR_ID) { if (blockToPick == Block.JAVA_AIR_ID) {
// Check for an item frame since the client thinks that's a block when it's an entity in Java // Check for an item frame since the client thinks that's a block when it's an entity in Java
ItemFrameEntity entity = ItemFrameEntity.getItemFrameEntity(session, packet.getBlockPosition()); ItemFrameEntity entity = ItemFrameEntity.getItemFrameEntity(session, packet.getBlockPosition());
if (entity != null) { if (entity != null) {

Datei anzeigen

@ -57,6 +57,7 @@ import org.geysermc.geyser.item.type.BoatItem;
import org.geysermc.geyser.item.type.Item; import org.geysermc.geyser.item.type.Item;
import org.geysermc.geyser.item.type.SpawnEggItem; import org.geysermc.geyser.item.type.SpawnEggItem;
import org.geysermc.geyser.level.block.BlockStateValues; import org.geysermc.geyser.level.block.BlockStateValues;
import org.geysermc.geyser.level.block.type.Block;
import org.geysermc.geyser.registry.BlockRegistries; import org.geysermc.geyser.registry.BlockRegistries;
import org.geysermc.geyser.session.GeyserSession; import org.geysermc.geyser.session.GeyserSession;
import org.geysermc.geyser.session.cache.SkullCache; import org.geysermc.geyser.session.cache.SkullCache;
@ -444,7 +445,7 @@ public class BedrockInventoryTransactionTranslator extends PacketTranslator<Inve
session.getWorldCache().markPositionInSequence(packet.getBlockPosition()); session.getWorldCache().markPositionInSequence(packet.getBlockPosition());
// -1 means we don't know what block they're breaking // -1 means we don't know what block they're breaking
if (blockState == -1) { if (blockState == -1) {
blockState = BlockStateValues.JAVA_AIR_ID; blockState = Block.JAVA_AIR_ID;
} }
LevelEventPacket blockBreakPacket = new LevelEventPacket(); LevelEventPacket blockBreakPacket = new LevelEventPacket();

Datei anzeigen

@ -39,6 +39,8 @@ import org.geysermc.geyser.entity.type.ItemFrameEntity;
import org.geysermc.geyser.entity.type.player.SessionPlayerEntity; import org.geysermc.geyser.entity.type.player.SessionPlayerEntity;
import org.geysermc.geyser.inventory.GeyserItemStack; import org.geysermc.geyser.inventory.GeyserItemStack;
import org.geysermc.geyser.level.block.BlockStateValues; import org.geysermc.geyser.level.block.BlockStateValues;
import org.geysermc.geyser.level.block.type.Block;
import org.geysermc.geyser.level.block.type.BlockState;
import org.geysermc.geyser.network.GameProtocol; import org.geysermc.geyser.network.GameProtocol;
import org.geysermc.geyser.registry.BlockRegistries; import org.geysermc.geyser.registry.BlockRegistries;
import org.geysermc.geyser.registry.type.BlockMapping; import org.geysermc.geyser.registry.type.BlockMapping;
@ -159,7 +161,7 @@ public class BedrockActionTranslator extends PacketTranslator<PlayerActionPacket
LevelEventPacket startBreak = new LevelEventPacket(); LevelEventPacket startBreak = new LevelEventPacket();
startBreak.setType(LevelEvent.BLOCK_START_BREAK); startBreak.setType(LevelEvent.BLOCK_START_BREAK);
startBreak.setPosition(vector.toFloat()); startBreak.setPosition(vector.toFloat());
double breakTime = BlockUtils.getSessionBreakTime(session, BlockRegistries.JAVA_BLOCKS.getOrDefault(blockState, BlockMapping.DEFAULT)) * 20; double breakTime = BlockUtils.getSessionBreakTime(session, BlockRegistries.BLOCK_STATES.getOrDefault(blockState, BlockState.of(Block.JAVA_AIR_ID)).block()) * 20;
// If the block is custom or the breaking item is custom, we must keep track of break time ourselves // If the block is custom or the breaking item is custom, we must keep track of break time ourselves
GeyserItemStack item = session.getPlayerInventory().getItemInHand(); GeyserItemStack item = session.getPlayerInventory().getItemInHand();
@ -197,7 +199,7 @@ public class BedrockActionTranslator extends PacketTranslator<PlayerActionPacket
} }
int breakingBlock = session.getBreakingBlock(); int breakingBlock = session.getBreakingBlock();
if (breakingBlock == -1) { if (breakingBlock == -1) {
breakingBlock = BlockStateValues.JAVA_AIR_ID; breakingBlock = Block.JAVA_AIR_ID;
} }
Vector3f vectorFloat = vector.toFloat(); Vector3f vectorFloat = vector.toFloat();
@ -211,7 +213,7 @@ public class BedrockActionTranslator extends PacketTranslator<PlayerActionPacket
LevelEventPacket updateBreak = new LevelEventPacket(); LevelEventPacket updateBreak = new LevelEventPacket();
updateBreak.setType(LevelEvent.BLOCK_UPDATE_BREAK); updateBreak.setType(LevelEvent.BLOCK_UPDATE_BREAK);
updateBreak.setPosition(vectorFloat); updateBreak.setPosition(vectorFloat);
double breakTime = BlockUtils.getSessionBreakTime(session, BlockRegistries.JAVA_BLOCKS.getOrDefault(breakingBlock, BlockMapping.DEFAULT)) * 20; double breakTime = BlockUtils.getSessionBreakTime(session, BlockRegistries.BLOCK_STATES.getOrDefault(breakingBlock, BlockState.of(Block.JAVA_AIR_ID)).block()) * 20;
// If the block is custom, we must keep track of when it should break ourselves // If the block is custom, we must keep track of when it should break ourselves

Datei anzeigen

@ -25,6 +25,7 @@
package org.geysermc.geyser.translator.protocol.java; package org.geysermc.geyser.translator.protocol.java;
import org.geysermc.erosion.Constants;
import org.geysermc.mcprotocollib.protocol.data.game.entity.player.PlayerSpawnInfo; import org.geysermc.mcprotocollib.protocol.data.game.entity.player.PlayerSpawnInfo;
import org.geysermc.mcprotocollib.protocol.packet.common.serverbound.ServerboundCustomPayloadPacket; import org.geysermc.mcprotocollib.protocol.packet.common.serverbound.ServerboundCustomPayloadPacket;
import org.geysermc.mcprotocollib.protocol.packet.ingame.clientbound.ClientboundLoginPacket; import org.geysermc.mcprotocollib.protocol.packet.ingame.clientbound.ClientboundLoginPacket;
@ -45,6 +46,8 @@ import org.geysermc.geyser.util.ChunkUtils;
import org.geysermc.geyser.util.DimensionUtils; import org.geysermc.geyser.util.DimensionUtils;
import org.geysermc.geyser.util.EntityUtils; import org.geysermc.geyser.util.EntityUtils;
import java.nio.charset.StandardCharsets;
@Translator(packet = ClientboundLoginPacket.class) @Translator(packet = ClientboundLoginPacket.class)
public class JavaLoginTranslator extends PacketTranslator<ClientboundLoginPacket> { public class JavaLoginTranslator extends PacketTranslator<ClientboundLoginPacket> {
@ -134,6 +137,7 @@ public class JavaLoginTranslator extends PacketTranslator<ClientboundLoginPacket
if (session.remoteServer().authType() == AuthType.FLOODGATE) { if (session.remoteServer().authType() == AuthType.FLOODGATE) {
session.sendDownstreamPacket(new ServerboundCustomPayloadPacket("minecraft:register", PluginMessageChannels.getFloodgateRegisterData())); session.sendDownstreamPacket(new ServerboundCustomPayloadPacket("minecraft:register", PluginMessageChannels.getFloodgateRegisterData()));
} }
session.sendDownstreamPacket(new ServerboundCustomPayloadPacket("minecraft:register", Constants.PLUGIN_MESSAGE.getBytes(StandardCharsets.UTF_8)));
if (newDimension != session.getDimension()) { if (newDimension != session.getDimension()) {
DimensionUtils.switchDimension(session, newDimension); DimensionUtils.switchDimension(session, newDimension);

Datei anzeigen

@ -0,0 +1,62 @@
/*
* Copyright (c) 2019-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.translator.protocol.java;
import org.geysermc.geyser.network.GameProtocol;
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.KnownPack;
import org.geysermc.mcprotocollib.protocol.packet.configuration.clientbound.ClientboundSelectKnownPacks;
import org.geysermc.mcprotocollib.protocol.packet.configuration.serverbound.ServerboundSelectKnownPacks;
import java.util.ArrayList;
import java.util.List;
import java.util.Set;
@Translator(packet = ClientboundSelectKnownPacks.class)
public class JavaSelectKnownPacksTranslator extends PacketTranslator<ClientboundSelectKnownPacks> {
// todo: dump from client?
private static final Set<String> KNOWN_PACK_IDS = Set.of("core", "update_1_21", "bundle", "trade_rebalance");
@Override
public void translate(GeyserSession session, ClientboundSelectKnownPacks packet) {
List<KnownPack> knownPacks = new ArrayList<>(1);
for (KnownPack pack : packet.getKnownPacks()) {
if ("minecraft".equals(pack.getNamespace()) && GameProtocol.getJavaMinecraftVersion().equals(pack.getVersion())) {
// Implementation note: these won't always necessarily be equal.
// 1.20.5 versus 1.20.6 for example - same protocol version. A vanilla server for either version will gracefully accept either.
// If the versions mismatch, the registry will be sent over the network, though.
// For vanilla compliancy, to minimize network traffic, and for potential future behavior,
// We'll implement how the Java client does it.
if (KNOWN_PACK_IDS.contains(pack.getId())) {
knownPacks.add(pack);
}
}
}
session.sendDownstreamPacket(new ServerboundSelectKnownPacks(knownPacks));
}
}

Datei anzeigen

@ -25,16 +25,17 @@
package org.geysermc.geyser.translator.protocol.java.level; package org.geysermc.geyser.translator.protocol.java.level;
import org.geysermc.mcprotocollib.protocol.packet.ingame.clientbound.level.ClientboundBlockDestructionPacket;
import org.cloudburstmc.protocol.bedrock.data.LevelEvent; import org.cloudburstmc.protocol.bedrock.data.LevelEvent;
import org.cloudburstmc.protocol.bedrock.packet.LevelEventPacket; import org.cloudburstmc.protocol.bedrock.packet.LevelEventPacket;
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.BlockRegistries;
import org.geysermc.geyser.registry.type.BlockMapping;
import org.geysermc.geyser.registry.type.ItemMapping; import org.geysermc.geyser.registry.type.ItemMapping;
import org.geysermc.geyser.session.GeyserSession; import org.geysermc.geyser.session.GeyserSession;
import org.geysermc.geyser.translator.protocol.PacketTranslator; import org.geysermc.geyser.translator.protocol.PacketTranslator;
import org.geysermc.geyser.translator.protocol.Translator; import org.geysermc.geyser.translator.protocol.Translator;
import org.geysermc.geyser.util.BlockUtils; import org.geysermc.geyser.util.BlockUtils;
import org.geysermc.mcprotocollib.protocol.packet.ingame.clientbound.level.ClientboundBlockDestructionPacket;
@Translator(packet = ClientboundBlockDestructionPacket.class) @Translator(packet = ClientboundBlockDestructionPacket.class)
public class JavaBlockDestructionTranslator extends PacketTranslator<ClientboundBlockDestructionPacket> { public class JavaBlockDestructionTranslator extends PacketTranslator<ClientboundBlockDestructionPacket> {
@ -42,7 +43,7 @@ public class JavaBlockDestructionTranslator extends PacketTranslator<Clientbound
@Override @Override
public void translate(GeyserSession session, ClientboundBlockDestructionPacket packet) { public void translate(GeyserSession session, ClientboundBlockDestructionPacket packet) {
int state = session.getGeyser().getWorldManager().getBlockAt(session, packet.getPosition().getX(), packet.getPosition().getY(), packet.getPosition().getZ()); int state = session.getGeyser().getWorldManager().getBlockAt(session, packet.getPosition().getX(), packet.getPosition().getY(), packet.getPosition().getZ());
int breakTime = (int) (65535 / Math.ceil(BlockUtils.getBreakTime(session, BlockRegistries.JAVA_BLOCKS.getOrDefault(state, BlockMapping.DEFAULT), ItemMapping.AIR, null, false) * 20)); int breakTime = (int) (65535 / Math.ceil(BlockUtils.getBreakTime(session, BlockRegistries.BLOCK_STATES.getOrDefault(state, BlockState.of(Block.JAVA_AIR_ID)).block(), ItemMapping.AIR, null, false) * 20));
LevelEventPacket levelEventPacket = new LevelEventPacket(); LevelEventPacket levelEventPacket = new LevelEventPacket();
levelEventPacket.setPosition(packet.getPosition().toFloat()); levelEventPacket.setPosition(packet.getPosition().toFloat());
levelEventPacket.setType(LevelEvent.BLOCK_START_BREAK); levelEventPacket.setType(LevelEvent.BLOCK_START_BREAK);

Datei anzeigen

@ -33,7 +33,8 @@ import org.cloudburstmc.protocol.bedrock.data.structure.StructureMirror;
import org.cloudburstmc.protocol.bedrock.data.structure.StructureRotation; import org.cloudburstmc.protocol.bedrock.data.structure.StructureRotation;
import org.cloudburstmc.protocol.bedrock.packet.ContainerOpenPacket; import org.cloudburstmc.protocol.bedrock.packet.ContainerOpenPacket;
import org.cloudburstmc.protocol.bedrock.packet.UpdateBlockPacket; import org.cloudburstmc.protocol.bedrock.packet.UpdateBlockPacket;
import org.geysermc.geyser.level.block.BlockStateValues; import org.geysermc.geyser.level.block.type.BlockState;
import org.geysermc.geyser.registry.BlockRegistries;
import org.geysermc.geyser.session.GeyserSession; import org.geysermc.geyser.session.GeyserSession;
import org.geysermc.geyser.translator.level.block.entity.BlockEntityTranslator; import org.geysermc.geyser.translator.level.block.entity.BlockEntityTranslator;
import org.geysermc.geyser.translator.level.block.entity.RequiresBlockState; import org.geysermc.geyser.translator.level.block.entity.RequiresBlockState;
@ -58,11 +59,11 @@ public class JavaBlockEntityDataTranslator extends PacketTranslator<ClientboundB
BlockEntityTranslator translator = BlockEntityUtils.getBlockEntityTranslator(type); BlockEntityTranslator translator = BlockEntityUtils.getBlockEntityTranslator(type);
// The Java block state is used in BlockEntityTranslator.translateTag() to make up for some inconsistencies // The Java block state is used in BlockEntityTranslator.translateTag() to make up for some inconsistencies
// between Java block states and Bedrock block entity data // between Java block states and Bedrock block entity data
int blockState; BlockState blockState;
if (translator instanceof RequiresBlockState) { if (translator instanceof RequiresBlockState) {
blockState = session.getGeyser().getWorldManager().getBlockAt(session, packet.getPosition()); blockState = BlockRegistries.BLOCK_STATES.get(session.getGeyser().getWorldManager().getBlockAt(session, packet.getPosition()));
} else { } else {
blockState = BlockStateValues.JAVA_AIR_ID; blockState = BlockRegistries.BLOCK_STATES.get(0); //TODO
} }
Vector3i position = packet.getPosition(); Vector3i position = packet.getPosition();
@ -71,7 +72,7 @@ public class JavaBlockEntityDataTranslator extends PacketTranslator<ClientboundB
// Check for custom skulls. // Check for custom skulls.
boolean hasCustomHeadBlock = false; boolean hasCustomHeadBlock = false;
if (session.getPreferencesCache().showCustomSkulls() && packet.getNbt() != null && packet.getNbt().containsKey("profile")) { if (session.getPreferencesCache().showCustomSkulls() && packet.getNbt() != null && packet.getNbt().containsKey("profile")) {
BlockDefinition blockDefinition = SkullBlockEntityTranslator.translateSkull(session, packet.getNbt(), position, blockState); BlockDefinition blockDefinition = SkullBlockEntityTranslator.translateSkull(session, packet.getNbt(), position, blockState.javaId());
if (blockDefinition != null) { if (blockDefinition != null) {
hasCustomHeadBlock = true; hasCustomHeadBlock = true;
UpdateBlockPacket updateBlockPacket = new UpdateBlockPacket(); UpdateBlockPacket updateBlockPacket = new UpdateBlockPacket();

Datei anzeigen

@ -25,6 +25,7 @@
package org.geysermc.geyser.translator.protocol.java.level; package org.geysermc.geyser.translator.protocol.java.level;
import org.geysermc.geyser.level.block.type.Block;
import org.geysermc.mcprotocollib.protocol.data.game.level.block.value.*; import org.geysermc.mcprotocollib.protocol.data.game.level.block.value.*;
import org.geysermc.mcprotocollib.protocol.packet.ingame.clientbound.level.ClientboundBlockEventPacket; import org.geysermc.mcprotocollib.protocol.packet.ingame.clientbound.level.ClientboundBlockEventPacket;
import org.cloudburstmc.math.vector.Vector3i; import org.cloudburstmc.math.vector.Vector3i;
@ -82,7 +83,7 @@ public class JavaBlockEventTranslator extends PacketTranslator<ClientboundBlockE
if (action != PistonValueType.CANCELLED_MID_PUSH) { if (action != PistonValueType.CANCELLED_MID_PUSH) {
Vector3i blockInFrontPos = position.add(direction.getUnitVector()); Vector3i blockInFrontPos = position.add(direction.getUnitVector());
int blockInFront = session.getGeyser().getWorldManager().getBlockAt(session, blockInFrontPos); int blockInFront = session.getGeyser().getWorldManager().getBlockAt(session, blockInFrontPos);
if (blockInFront != BlockStateValues.JAVA_AIR_ID) { if (blockInFront != Block.JAVA_AIR_ID) {
// Piston pulled something // Piston pulled something
return; return;
} }

Datei anzeigen

@ -25,6 +25,7 @@
package org.geysermc.geyser.translator.protocol.java.level; package org.geysermc.geyser.translator.protocol.java.level;
import org.geysermc.geyser.level.block.type.Block;
import org.geysermc.mcprotocollib.protocol.packet.ingame.clientbound.level.ClientboundExplodePacket; import org.geysermc.mcprotocollib.protocol.packet.ingame.clientbound.level.ClientboundExplodePacket;
import org.cloudburstmc.math.vector.Vector3f; import org.cloudburstmc.math.vector.Vector3f;
import org.cloudburstmc.math.vector.Vector3i; import org.cloudburstmc.math.vector.Vector3i;
@ -58,7 +59,7 @@ public class JavaExplodeTranslator extends PacketTranslator<ClientboundExplodePa
int i = 0; int i = 0;
for (Vector3i position : packet.getExploded()) { for (Vector3i position : packet.getExploded()) {
Vector3i pos = Vector3i.from(packet.getX() + position.getX(), packet.getY() + position.getY(), packet.getZ() + position.getZ()); Vector3i pos = Vector3i.from(packet.getX() + position.getX(), packet.getY() + position.getY(), packet.getZ() + position.getZ());
ChunkUtils.updateBlock(session, BlockStateValues.JAVA_AIR_ID, pos); ChunkUtils.updateBlock(session, Block.JAVA_AIR_ID, pos);
builder.putFloat("pos" + i + "x", pos.getX()); builder.putFloat("pos" + i + "x", pos.getX());
builder.putFloat("pos" + i + "y", pos.getY()); builder.putFloat("pos" + i + "y", pos.getY());
builder.putFloat("pos" + i + "z", pos.getZ()); builder.putFloat("pos" + i + "z", pos.getZ());

Datei anzeigen

@ -42,6 +42,9 @@ import org.geysermc.erosion.util.LecternUtils;
import org.geysermc.geyser.entity.type.ItemFrameEntity; import org.geysermc.geyser.entity.type.ItemFrameEntity;
import org.geysermc.geyser.level.BedrockDimension; import org.geysermc.geyser.level.BedrockDimension;
import org.geysermc.geyser.level.block.BlockStateValues; import org.geysermc.geyser.level.block.BlockStateValues;
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.level.chunk.BlockStorage; import org.geysermc.geyser.level.chunk.BlockStorage;
import org.geysermc.geyser.level.chunk.GeyserChunkSection; import org.geysermc.geyser.level.chunk.GeyserChunkSection;
import org.geysermc.geyser.level.chunk.bitarray.BitArray; import org.geysermc.geyser.level.chunk.bitarray.BitArray;
@ -175,7 +178,7 @@ public class JavaLevelChunkWithLightTranslator extends PacketTranslator<Clientbo
// Extended collision blocks // Extended collision blocks
if (useExtendedCollisions) { if (useExtendedCollisions) {
if (EXTENDED_COLLISIONS_STORAGE.get().get(yzx, sectionY) != 0) { if (EXTENDED_COLLISIONS_STORAGE.get().get(yzx, sectionY) != 0) {
if (javaId == BlockStateValues.JAVA_AIR_ID) { if (javaId == Block.JAVA_AIR_ID) {
section.getBlockStorageArray()[0].setFullBlock(xzy, EXTENDED_COLLISIONS_STORAGE.get().get(yzx, sectionY)); section.getBlockStorageArray()[0].setFullBlock(xzy, EXTENDED_COLLISIONS_STORAGE.get().get(yzx, sectionY));
} }
EXTENDED_COLLISIONS_STORAGE.get().set(yzx, 0, sectionY); EXTENDED_COLLISIONS_STORAGE.get().set(yzx, 0, sectionY);
@ -238,7 +241,7 @@ public class JavaLevelChunkWithLightTranslator extends PacketTranslator<Clientbo
waterloggedPaletteIds.set(i); waterloggedPaletteIds.set(i);
} }
if (javaId == BlockStateValues.JAVA_AIR_ID) { if (javaId == Block.JAVA_AIR_ID) {
airPaletteId = i; airPaletteId = i;
} }
@ -396,9 +399,9 @@ public class JavaLevelChunkWithLightTranslator extends PacketTranslator<Clientbo
// Get the Java block state ID from block entity position // Get the Java block state ID from block entity position
DataPalette section = javaChunks[(y >> 4) - yOffset]; DataPalette section = javaChunks[(y >> 4) - yOffset];
int blockState = section.get(x, y & 0xF, z); BlockState blockState = BlockRegistries.BLOCK_STATES.get(section.get(x, y & 0xF, z));
if (type == BlockEntityType.LECTERN && BlockStateValues.getLecternBookStates().get(blockState)) { if (type == BlockEntityType.LECTERN && blockState.getValue(Properties.HAS_BOOK)) {
// If getLecternBookStates is false, let's just treat it like a normal block entity // If getLecternBookStates is false, let's just treat it like a normal block entity
// Fill in tag with a default value // Fill in tag with a default value
NbtMapBuilder lecternTag = LecternUtils.getBaseLecternTag(x + chunkBlockX, y, z + chunkBlockZ, 1); NbtMapBuilder lecternTag = LecternUtils.getBaseLecternTag(x + chunkBlockX, y, z + chunkBlockZ, 1);
@ -419,7 +422,7 @@ public class JavaLevelChunkWithLightTranslator extends PacketTranslator<Clientbo
// Check for custom skulls // Check for custom skulls
if (session.getPreferencesCache().showCustomSkulls() && type == BlockEntityType.SKULL && tag != null && tag.containsKey("profile")) { if (session.getPreferencesCache().showCustomSkulls() && type == BlockEntityType.SKULL && tag != null && tag.containsKey("profile")) {
BlockDefinition blockDefinition = SkullBlockEntityTranslator.translateSkull(session, tag, Vector3i.from(x + chunkBlockX, y, z + chunkBlockZ), blockState); BlockDefinition blockDefinition = SkullBlockEntityTranslator.translateSkull(session, tag, Vector3i.from(x + chunkBlockX, y, z + chunkBlockZ), blockState.javaId());
if (blockDefinition != null) { if (blockDefinition != null) {
int bedrockSectionY = (y >> 4) - (bedrockDimension.minY() >> 4); int bedrockSectionY = (y >> 4) - (bedrockDimension.minY() >> 4);
int subChunkIndex = (y >> 4) + (bedrockDimension.minY() >> 4); int subChunkIndex = (y >> 4) + (bedrockDimension.minY() >> 4);

Datei anzeigen

@ -30,9 +30,9 @@ import org.cloudburstmc.math.vector.Vector3i;
import org.geysermc.geyser.inventory.GeyserItemStack; import org.geysermc.geyser.inventory.GeyserItemStack;
import org.geysermc.geyser.inventory.PlayerInventory; import org.geysermc.geyser.inventory.PlayerInventory;
import org.geysermc.geyser.inventory.item.Enchantment; import org.geysermc.geyser.inventory.item.Enchantment;
import org.geysermc.geyser.level.block.BlockStateValues; import org.geysermc.geyser.level.block.Blocks;
import org.geysermc.geyser.level.block.type.Block;
import org.geysermc.geyser.registry.BlockRegistries; import org.geysermc.geyser.registry.BlockRegistries;
import org.geysermc.geyser.registry.type.BlockMapping;
import org.geysermc.geyser.registry.type.ItemMapping; import org.geysermc.geyser.registry.type.ItemMapping;
import org.geysermc.geyser.session.GeyserSession; import org.geysermc.geyser.session.GeyserSession;
import org.geysermc.geyser.session.cache.tags.BlockTag; import org.geysermc.geyser.session.cache.tags.BlockTag;
@ -41,14 +41,14 @@ import org.geysermc.mcprotocollib.protocol.data.game.item.component.DataComponen
public final class BlockUtils { public final class BlockUtils {
private static boolean correctTool(GeyserSession session, BlockMapping blockMapping, String itemToolType) { private static boolean correctTool(GeyserSession session, Block block, String itemToolType) {
return switch (itemToolType) { return switch (itemToolType) {
case "axe" -> session.getTagCache().is(BlockTag.AXE_EFFECTIVE, blockMapping); case "axe" -> session.getTagCache().is(BlockTag.AXE_EFFECTIVE, block);
case "hoe" -> session.getTagCache().is(BlockTag.HOE_EFFECTIVE, blockMapping); case "hoe" -> session.getTagCache().is(BlockTag.HOE_EFFECTIVE, block);
case "pickaxe" -> session.getTagCache().is(BlockTag.PICKAXE_EFFECTIVE, blockMapping); case "pickaxe" -> session.getTagCache().is(BlockTag.PICKAXE_EFFECTIVE, block);
case "shears" -> session.getTagCache().is(BlockTag.LEAVES, blockMapping) || session.getTagCache().is(BlockTag.WOOL, blockMapping); case "shears" -> session.getTagCache().is(BlockTag.LEAVES, block) || session.getTagCache().is(BlockTag.WOOL, block);
case "shovel" -> session.getTagCache().is(BlockTag.SHOVEL_EFFECTIVE, blockMapping); case "shovel" -> session.getTagCache().is(BlockTag.SHOVEL_EFFECTIVE, block);
case "sword" -> blockMapping.getJavaBlockId() == BlockStateValues.JAVA_COBWEB_ID; case "sword" -> block == Blocks.COBWEB;
default -> { default -> {
session.getGeyser().getLogger().warning("Unknown tool type: " + itemToolType); session.getGeyser().getLogger().warning("Unknown tool type: " + itemToolType);
yield false; yield false;
@ -71,7 +71,7 @@ public final class BlockUtils {
}; };
} }
private static boolean canToolTierBreakBlock(GeyserSession session, BlockMapping blockMapping, String toolTier) { private static boolean canToolTierBreakBlock(GeyserSession session, Block block, String toolTier) {
if (toolTier.equals("netherite") || toolTier.equals("diamond")) { if (toolTier.equals("netherite") || toolTier.equals("diamond")) {
// As of 1.17, these tiers can mine everything that is mineable // As of 1.17, these tiers can mine everything that is mineable
return true; return true;
@ -80,15 +80,15 @@ public final class BlockUtils {
switch (toolTier) { switch (toolTier) {
// Use intentional fall-throughs to check each tier with this block // Use intentional fall-throughs to check each tier with this block
default: default:
if (session.getTagCache().is(BlockTag.NEEDS_STONE_TOOL, blockMapping)) { if (session.getTagCache().is(BlockTag.NEEDS_STONE_TOOL, block)) {
return false; return false;
} }
case "stone": case "stone":
if (session.getTagCache().is(BlockTag.NEEDS_IRON_TOOL, blockMapping)) { if (session.getTagCache().is(BlockTag.NEEDS_IRON_TOOL, block)) {
return false; return false;
} }
case "iron": case "iron":
if (session.getTagCache().is(BlockTag.NEEDS_DIAMOND_TOOL, blockMapping)) { if (session.getTagCache().is(BlockTag.NEEDS_DIAMOND_TOOL, block)) {
return false; return false;
} }
} }
@ -131,9 +131,9 @@ public final class BlockUtils {
return 1.0 / speed; return 1.0 / speed;
} }
public static double getBreakTime(GeyserSession session, BlockMapping blockMapping, ItemMapping item, @Nullable DataComponents components, boolean isSessionPlayer) { public static double getBreakTime(GeyserSession session, Block block, ItemMapping item, @Nullable DataComponents components, boolean isSessionPlayer) {
boolean isShearsEffective = session.getTagCache().is(BlockTag.LEAVES, blockMapping) || session.getTagCache().is(BlockTag.WOOL, blockMapping); //TODO called twice boolean isShearsEffective = session.getTagCache().is(BlockTag.LEAVES, block) || session.getTagCache().is(BlockTag.WOOL, block); //TODO called twice
boolean canHarvestWithHand = blockMapping.isCanBreakWithHand(); boolean canHarvestWithHand = !block.requiresCorrectToolForDrops();
String toolType = ""; String toolType = "";
String toolTier = ""; String toolTier = "";
boolean correctTool = false; boolean correctTool = false;
@ -141,8 +141,8 @@ public final class BlockUtils {
if (item.isTool()) { if (item.isTool()) {
toolType = item.getToolType(); toolType = item.getToolType();
toolTier = item.getToolTier(); toolTier = item.getToolTier();
correctTool = correctTool(session, blockMapping, toolType); correctTool = correctTool(session, block, toolType);
toolCanBreak = canToolTierBreakBlock(session, blockMapping, toolTier); toolCanBreak = canToolTierBreakBlock(session, block, toolTier);
} }
int toolEfficiencyLevel = ItemUtils.getEnchantmentLevel(components, Enchantment.JavaEnchantment.EFFICIENCY); int toolEfficiencyLevel = ItemUtils.getEnchantmentLevel(components, Enchantment.JavaEnchantment.EFFICIENCY);
@ -151,7 +151,7 @@ public final class BlockUtils {
if (!isSessionPlayer) { if (!isSessionPlayer) {
// Another entity is currently mining; we have all the information we know // Another entity is currently mining; we have all the information we know
return calculateBreakTime(blockMapping.getHardness(), toolTier, canHarvestWithHand, correctTool, toolCanBreak, toolType, isShearsEffective, return calculateBreakTime(block.destroyTime(), toolTier, canHarvestWithHand, correctTool, toolCanBreak, toolType, isShearsEffective,
toolEfficiencyLevel, hasteLevel, miningFatigueLevel, false, true); toolEfficiencyLevel, hasteLevel, miningFatigueLevel, false, true);
} }
@ -162,11 +162,11 @@ public final class BlockUtils {
boolean insideOfWaterWithoutAquaAffinity = waterInEyes && boolean insideOfWaterWithoutAquaAffinity = waterInEyes &&
ItemUtils.getEnchantmentLevel(session.getPlayerInventory().getItem(5).getComponents(), Enchantment.JavaEnchantment.AQUA_AFFINITY) < 1; ItemUtils.getEnchantmentLevel(session.getPlayerInventory().getItem(5).getComponents(), Enchantment.JavaEnchantment.AQUA_AFFINITY) < 1;
return calculateBreakTime(blockMapping.getHardness(), toolTier, canHarvestWithHand, correctTool, toolCanBreak, toolType, isShearsEffective, return calculateBreakTime(block.destroyTime(), toolTier, canHarvestWithHand, correctTool, toolCanBreak, toolType, isShearsEffective,
toolEfficiencyLevel, hasteLevel, miningFatigueLevel, insideOfWaterWithoutAquaAffinity, session.getPlayerEntity().isOnGround()); toolEfficiencyLevel, hasteLevel, miningFatigueLevel, insideOfWaterWithoutAquaAffinity, session.getPlayerEntity().isOnGround());
} }
public static double getSessionBreakTime(GeyserSession session, BlockMapping blockMapping) { public static double getSessionBreakTime(GeyserSession session, Block block) {
PlayerInventory inventory = session.getPlayerInventory(); PlayerInventory inventory = session.getPlayerInventory();
GeyserItemStack item = inventory.getItemInHand(); GeyserItemStack item = inventory.getItemInHand();
ItemMapping mapping = ItemMapping.AIR; ItemMapping mapping = ItemMapping.AIR;
@ -175,7 +175,7 @@ public final class BlockUtils {
mapping = item.getMapping(session); mapping = item.getMapping(session);
components = item.getComponents(); components = item.getComponents();
} }
return getBreakTime(session, blockMapping, mapping, components, true); return getBreakTime(session, block, mapping, components, true);
} }
/** /**

Datei anzeigen

@ -41,6 +41,8 @@ import org.geysermc.geyser.entity.type.ItemFrameEntity;
import org.geysermc.geyser.level.BedrockDimension; import org.geysermc.geyser.level.BedrockDimension;
import org.geysermc.geyser.level.JavaDimension; import org.geysermc.geyser.level.JavaDimension;
import org.geysermc.geyser.level.block.BlockStateValues; import org.geysermc.geyser.level.block.BlockStateValues;
import org.geysermc.geyser.level.block.type.Block;
import org.geysermc.geyser.level.block.type.BlockState;
import org.geysermc.geyser.level.chunk.BlockStorage; import org.geysermc.geyser.level.chunk.BlockStorage;
import org.geysermc.geyser.level.chunk.GeyserChunkSection; import org.geysermc.geyser.level.chunk.GeyserChunkSection;
import org.geysermc.geyser.level.chunk.bitarray.SingletonBitArray; import org.geysermc.geyser.level.chunk.bitarray.SingletonBitArray;
@ -50,8 +52,6 @@ import org.geysermc.geyser.session.cache.SkullCache;
import org.geysermc.geyser.text.GeyserLocale; import org.geysermc.geyser.text.GeyserLocale;
import org.geysermc.geyser.translator.level.block.entity.BedrockOnlyBlockEntity; import org.geysermc.geyser.translator.level.block.entity.BedrockOnlyBlockEntity;
import static org.geysermc.geyser.level.block.BlockStateValues.JAVA_AIR_ID;
@UtilityClass @UtilityClass
public class ChunkUtils { public class ChunkUtils {
@ -130,7 +130,7 @@ public class ChunkUtils {
// Checks for item frames so they aren't tripped up and removed // Checks for item frames so they aren't tripped up and removed
ItemFrameEntity itemFrameEntity = ItemFrameEntity.getItemFrameEntity(session, position); ItemFrameEntity itemFrameEntity = ItemFrameEntity.getItemFrameEntity(session, position);
if (itemFrameEntity != null) { if (itemFrameEntity != null) {
if (blockState == JAVA_AIR_ID) { // Item frame is still present and no block overrides that; refresh it if (blockState == Block.JAVA_AIR_ID) { // Item frame is still present and no block overrides that; refresh it
itemFrameEntity.updateBlock(true); itemFrameEntity.updateBlock(true);
// Still update the chunk cache with the new block if updateBlock is called // Still update the chunk cache with the new block if updateBlock is called
return; return;
@ -180,21 +180,21 @@ public class ChunkUtils {
BlockDefinition aboveBedrockExtendedCollisionDefinition = session.getBlockMappings().getExtendedCollisionBoxes().get(blockState); BlockDefinition aboveBedrockExtendedCollisionDefinition = session.getBlockMappings().getExtendedCollisionBoxes().get(blockState);
int belowBlock = session.getGeyser().getWorldManager().getBlockAt(session, position.getX(), position.getY() - 1, position.getZ()); int belowBlock = session.getGeyser().getWorldManager().getBlockAt(session, position.getX(), position.getY() - 1, position.getZ());
BlockDefinition belowBedrockExtendedCollisionDefinition = session.getBlockMappings().getExtendedCollisionBoxes().get(belowBlock); BlockDefinition belowBedrockExtendedCollisionDefinition = session.getBlockMappings().getExtendedCollisionBoxes().get(belowBlock);
if (belowBedrockExtendedCollisionDefinition != null && blockState == BlockStateValues.JAVA_AIR_ID) { if (belowBedrockExtendedCollisionDefinition != null && blockState == Block.JAVA_AIR_ID) {
UpdateBlockPacket updateBlockPacket = new UpdateBlockPacket(); UpdateBlockPacket updateBlockPacket = new UpdateBlockPacket();
updateBlockPacket.setDataLayer(0); updateBlockPacket.setDataLayer(0);
updateBlockPacket.setBlockPosition(position); updateBlockPacket.setBlockPosition(position);
updateBlockPacket.setDefinition(belowBedrockExtendedCollisionDefinition); updateBlockPacket.setDefinition(belowBedrockExtendedCollisionDefinition);
updateBlockPacket.getFlags().add(UpdateBlockPacket.Flag.NETWORK); updateBlockPacket.getFlags().add(UpdateBlockPacket.Flag.NETWORK);
session.sendUpstreamPacket(updateBlockPacket); session.sendUpstreamPacket(updateBlockPacket);
} else if (aboveBedrockExtendedCollisionDefinition != null && aboveBlock == BlockStateValues.JAVA_AIR_ID) { } else if (aboveBedrockExtendedCollisionDefinition != null && aboveBlock == Block.JAVA_AIR_ID) {
UpdateBlockPacket updateBlockPacket = new UpdateBlockPacket(); UpdateBlockPacket updateBlockPacket = new UpdateBlockPacket();
updateBlockPacket.setDataLayer(0); updateBlockPacket.setDataLayer(0);
updateBlockPacket.setBlockPosition(position.add(0, 1, 0)); updateBlockPacket.setBlockPosition(position.add(0, 1, 0));
updateBlockPacket.setDefinition(aboveBedrockExtendedCollisionDefinition); updateBlockPacket.setDefinition(aboveBedrockExtendedCollisionDefinition);
updateBlockPacket.getFlags().add(UpdateBlockPacket.Flag.NETWORK); updateBlockPacket.getFlags().add(UpdateBlockPacket.Flag.NETWORK);
session.sendUpstreamPacket(updateBlockPacket); session.sendUpstreamPacket(updateBlockPacket);
} else if (aboveBlock == BlockStateValues.JAVA_AIR_ID) { } else if (aboveBlock == Block.JAVA_AIR_ID) {
UpdateBlockPacket updateBlockPacket = new UpdateBlockPacket(); UpdateBlockPacket updateBlockPacket = new UpdateBlockPacket();
updateBlockPacket.setDataLayer(0); updateBlockPacket.setDataLayer(0);
updateBlockPacket.setBlockPosition(position.add(0, 1, 0)); updateBlockPacket.setBlockPosition(position.add(0, 1, 0));
@ -211,7 +211,7 @@ public class ChunkUtils {
for (BedrockOnlyBlockEntity bedrockOnlyBlockEntity : BlockEntityUtils.BEDROCK_ONLY_BLOCK_ENTITIES) { for (BedrockOnlyBlockEntity bedrockOnlyBlockEntity : BlockEntityUtils.BEDROCK_ONLY_BLOCK_ENTITIES) {
if (bedrockOnlyBlockEntity.isBlock(blockState)) { if (bedrockOnlyBlockEntity.isBlock(blockState)) {
// Flower pots are block entities only in Bedrock and are not updated anywhere else like note blocks // Flower pots are block entities only in Bedrock and are not updated anywhere else like note blocks
bedrockOnlyBlockEntity.updateBlock(session, blockState, position); bedrockOnlyBlockEntity.updateBlock(session, BlockState.of(blockState), position); //TODO blockState
break; //No block will be a part of two classes break; //No block will be a part of two classes
} }
} }

Datei anzeigen

@ -34,6 +34,7 @@ import org.cloudburstmc.protocol.bedrock.packet.LevelSoundEventPacket;
import org.cloudburstmc.protocol.bedrock.packet.PlaySoundPacket; import org.cloudburstmc.protocol.bedrock.packet.PlaySoundPacket;
import org.geysermc.geyser.GeyserImpl; import org.geysermc.geyser.GeyserImpl;
import org.geysermc.geyser.level.block.BlockStateValues; import org.geysermc.geyser.level.block.BlockStateValues;
import org.geysermc.geyser.level.block.type.Block;
import org.geysermc.geyser.registry.BlockRegistries; import org.geysermc.geyser.registry.BlockRegistries;
import org.geysermc.geyser.registry.Registries; import org.geysermc.geyser.registry.Registries;
import org.geysermc.geyser.registry.type.SoundMapping; import org.geysermc.geyser.registry.type.SoundMapping;
@ -147,7 +148,7 @@ public final class SoundUtils {
soundPacket.setExtraData(soundMapping.getExtraData() + (int)(Math.round((Math.log10(pitch) / Math.log10(2)) * 12)) + 12); soundPacket.setExtraData(soundMapping.getExtraData() + (int)(Math.round((Math.log10(pitch) / Math.log10(2)) * 12)) + 12);
} else if (sound == SoundEvent.PLACE && soundMapping.getExtraData() == -1) { } else if (sound == SoundEvent.PLACE && soundMapping.getExtraData() == -1) {
if (!soundMapping.getIdentifier().equals(":")) { if (!soundMapping.getIdentifier().equals(":")) {
int javaId = BlockRegistries.JAVA_IDENTIFIER_TO_ID.get().getOrDefault(soundMapping.getIdentifier(), BlockStateValues.JAVA_AIR_ID); int javaId = BlockRegistries.JAVA_IDENTIFIER_TO_ID.get().getOrDefault(soundMapping.getIdentifier(), Block.JAVA_AIR_ID);
soundPacket.setExtraData(session.getBlockMappings().getBedrockBlockId(javaId)); soundPacket.setExtraData(session.getBlockMappings().getBedrockBlockId(javaId));
} else { } else {
session.getGeyser().getLogger().debug("PLACE sound mapping identifier was invalid! Please report: " + soundMapping); session.getGeyser().getLogger().debug("PLACE sound mapping identifier was invalid! Please report: " + soundMapping);

Datei anzeigen

@ -29,6 +29,7 @@ import it.unimi.dsi.fastutil.objects.Object2IntMap;
import org.geysermc.cumulus.form.SimpleForm; import org.geysermc.cumulus.form.SimpleForm;
import org.geysermc.cumulus.util.FormImage; import org.geysermc.cumulus.util.FormImage;
import org.geysermc.geyser.item.type.Item; 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.BlockRegistries;
import org.geysermc.geyser.registry.Registries; import org.geysermc.geyser.registry.Registries;
import org.geysermc.geyser.session.GeyserSession; import org.geysermc.geyser.session.GeyserSession;
@ -93,10 +94,10 @@ public class StatisticsUtils {
for (Object2IntMap.Entry<Statistic> entry : session.getStatistics().object2IntEntrySet()) { for (Object2IntMap.Entry<Statistic> entry : session.getStatistics().object2IntEntrySet()) {
if (entry.getKey() instanceof BreakBlockStatistic statistic) { if (entry.getKey() instanceof BreakBlockStatistic statistic) {
String identifier = BlockRegistries.CLEAN_JAVA_IDENTIFIERS.get(statistic.getId()); Block block = BlockRegistries.JAVA_BLOCKS_TO_RENAME.get(statistic.getId());
if (identifier != null) { if (block != null) {
String block = identifier.replace("minecraft:", "block.minecraft."); String identifier = block.javaIdentifier().replace("minecraft:", "block.minecraft.");
content.add(block + ": " + entry.getIntValue()); content.add(identifier + ": " + entry.getIntValue());
} }
} }
} }

@ -1 +1 @@
Subproject commit 7c01501ed6a0ee8848a66d729000539f2661f785 Subproject commit 6b661f0d517d895aebc1f55a25d2c86f033beb1d

Datei anzeigen

@ -1,7 +1,7 @@
[versions] [versions]
base-api = "1.0.0-SNAPSHOT" base-api = "1.0.0-SNAPSHOT"
cumulus = "1.1.2" cumulus = "1.1.2"
erosion = "1.0-20230406.174837-8" erosion = "1.1-20240515.191456-1"
events = "1.1-SNAPSHOT" events = "1.1-SNAPSHOT"
jackson = "2.17.0" jackson = "2.17.0"
fastutil = "8.5.2" fastutil = "8.5.2"
@ -15,7 +15,7 @@ protocol-connection = "3.0.0.Beta1-20240411.165033-128"
raknet = "1.0.0.CR3-20240416.144209-1" raknet = "1.0.0.CR3-20240416.144209-1"
blockstateupdater="1.20.80-20240411.142413-1" blockstateupdater="1.20.80-20240411.142413-1"
mcauthlib = "e5b0bcc" mcauthlib = "e5b0bcc"
mcprotocollib = "42ea4a4" # Revert from jitpack after release mcprotocollib = "1.20.6-2-20240515.051848-2" # Revert from jitpack after release
adventure = "4.14.0" adventure = "4.14.0"
adventure-platform = "4.3.0" adventure-platform = "4.3.0"
junit = "5.9.2" junit = "5.9.2"
@ -52,6 +52,7 @@ cumulus = { group = "org.geysermc.cumulus", name = "cumulus", version.ref = "cum
events = { group = "org.geysermc.event", name = "events", version.ref = "events" } events = { group = "org.geysermc.event", name = "events", version.ref = "events" }
erosion-bukkit-common = { group = "org.geysermc.erosion", name = "bukkit-common", version.ref = "erosion" } erosion-bukkit-common = { group = "org.geysermc.erosion", name = "bukkit-common", version.ref = "erosion" }
erosion-bukkit-nms = { group = "org.geysermc.erosion", name = "bukkit-nms", version.ref = "erosion" }
erosion-common = { group = "org.geysermc.erosion", name = "common", version.ref = "erosion" } erosion-common = { group = "org.geysermc.erosion", name = "common", version.ref = "erosion" }
jackson-annotations = { group = "com.fasterxml.jackson.core", name = "jackson-annotations", version.ref = "jackson" } jackson-annotations = { group = "com.fasterxml.jackson.core", name = "jackson-annotations", version.ref = "jackson" }
@ -64,6 +65,7 @@ fastutil-int-byte-maps = { group = "com.nukkitx.fastutil", name = "fastutil-int-
fastutil-int-boolean-maps = { group = "com.nukkitx.fastutil", name = "fastutil-int-boolean-maps", version.ref = "fastutil" } fastutil-int-boolean-maps = { group = "com.nukkitx.fastutil", name = "fastutil-int-boolean-maps", version.ref = "fastutil" }
fastutil-object-int-maps = { group = "com.nukkitx.fastutil", name = "fastutil-object-int-maps", version.ref = "fastutil" } fastutil-object-int-maps = { group = "com.nukkitx.fastutil", name = "fastutil-object-int-maps", version.ref = "fastutil" }
fastutil-object-object-maps = { group = "com.nukkitx.fastutil", name = "fastutil-object-object-maps", version.ref = "fastutil" } fastutil-object-object-maps = { group = "com.nukkitx.fastutil", name = "fastutil-object-object-maps", version.ref = "fastutil" }
fastutil-reference-object-maps = { group = "com.nukkitx.fastutil", name = "fastutil-reference-object-maps", version.ref = "fastutil" }
adventure-text-serializer-gson = { group = "net.kyori", name = "adventure-text-serializer-gson", version.ref = "adventure" } # Remove when we remove our Adventure bump adventure-text-serializer-gson = { group = "net.kyori", name = "adventure-text-serializer-gson", version.ref = "adventure" } # Remove when we remove our Adventure bump
adventure-text-serializer-legacy = { group = "net.kyori", name = "adventure-text-serializer-legacy", version.ref = "adventure" } adventure-text-serializer-legacy = { group = "net.kyori", name = "adventure-text-serializer-legacy", version.ref = "adventure" }
@ -108,7 +110,7 @@ guava = { group = "com.google.guava", name = "guava", version.ref = "guava" }
gson = { group = "com.google.code.gson", name = "gson", version.ref = "gson" } gson = { group = "com.google.code.gson", name = "gson", version.ref = "gson" }
junit = { group = "org.junit.jupiter", name = "junit-jupiter", version.ref = "junit" } junit = { group = "org.junit.jupiter", name = "junit-jupiter", version.ref = "junit" }
mcauthlib = { group = "com.github.GeyserMC", name = "MCAuthLib", version.ref = "mcauthlib" } mcauthlib = { group = "com.github.GeyserMC", name = "MCAuthLib", version.ref = "mcauthlib" }
mcprotocollib = { group = "com.github.geysermc", name = "mcprotocollib", version.ref = "mcprotocollib" } mcprotocollib = { group = "org.geysermc.mcprotocollib", name = "protocol", version.ref = "mcprotocollib" }
raknet = { group = "org.cloudburstmc.netty", name = "netty-transport-raknet", version.ref = "raknet" } raknet = { group = "org.cloudburstmc.netty", name = "netty-transport-raknet", version.ref = "raknet" }
terminalconsoleappender = { group = "net.minecrell", name = "terminalconsoleappender", version.ref = "terminalconsoleappender" } terminalconsoleappender = { group = "net.minecrell", name = "terminalconsoleappender", version.ref = "terminalconsoleappender" }
velocity-api = { group = "com.velocitypowered", name = "velocity-api", version.ref = "velocity" } velocity-api = { group = "com.velocitypowered", name = "velocity-api", version.ref = "velocity" }
@ -141,7 +143,7 @@ blossom = { id = "net.kyori.blossom", version.ref = "blossom" }
[bundles] [bundles]
jackson = [ "jackson-annotations", "jackson-core", "jackson-dataformat-yaml" ] jackson = [ "jackson-annotations", "jackson-core", "jackson-dataformat-yaml" ]
fastutil = [ "fastutil-int-int-maps", "fastutil-int-long-maps", "fastutil-int-byte-maps", "fastutil-int-boolean-maps", "fastutil-object-int-maps", "fastutil-object-object-maps" ] fastutil = [ "fastutil-int-int-maps", "fastutil-int-long-maps", "fastutil-int-byte-maps", "fastutil-int-boolean-maps", "fastutil-object-int-maps", "fastutil-object-object-maps", "fastutil-reference-object-maps" ]
adventure = [ "adventure-text-serializer-gson", "adventure-text-serializer-legacy", "adventure-text-serializer-plain" ] adventure = [ "adventure-text-serializer-gson", "adventure-text-serializer-legacy", "adventure-text-serializer-plain" ]
log4j = [ "log4j-api", "log4j-core", "log4j-slf4j2-impl" ] log4j = [ "log4j-api", "log4j-core", "log4j-slf4j2-impl" ]
jline = [ "jline-terminal", "jline-terminal-jna", "jline-reader" ] jline = [ "jline-terminal", "jline-terminal-jna", "jline-reader" ]