Start on 1.20.5 mod platform support - NeoForge (temporarily) excluded

Also fixes lecterns, and block break speed calculations
This commit is contained in:
onebeastchris 2024-04-22 23:36:48 +02:00 committed by Camotoy
parent c34f0f2c3b
commit 6a5efa3c9d
No known key found for this signature in database
GPG key ID: 7EEFB66FE798081F
15 changed files with 110 additions and 179 deletions

View file

@ -64,7 +64,7 @@ jobs:
with: with:
name: Geyser NeoForge name: Geyser NeoForge
path: geyser/bootstrap/mod/neoforge/build/libs/Geyser-NeoForge.jar path: geyser/bootstrap/mod/neoforge/build/libs/Geyser-NeoForge.jar
if-no-files-found: error #if-no-files-found: error // TODO 1.20.5 until neoforge updates
- name: Archive artifacts (Geyser Standalone) - name: Archive artifacts (Geyser Standalone)
uses: actions/upload-artifact@5d5d22a31266ced268874388b861e4b58bb5c2f3 uses: actions/upload-artifact@5d5d22a31266ced268874388b861e4b58bb5c2f3
if: success() if: success()

View file

@ -68,7 +68,7 @@ jobs:
with: with:
name: Geyser NeoForge name: Geyser NeoForge
path: bootstrap/mod/neoforge/build/libs/Geyser-NeoForge.jar path: bootstrap/mod/neoforge/build/libs/Geyser-NeoForge.jar
if-no-files-found: error #if-no-files-found: error // TODO 1.20.5 - currently no neoforge artifacts
- name: Archive artifacts (Geyser Standalone) - name: Archive artifacts (Geyser Standalone)
uses: actions/upload-artifact@5d5d22a31266ced268874388b861e4b58bb5c2f3 uses: actions/upload-artifact@5d5d22a31266ced268874388b861e4b58bb5c2f3
if: success() if: success()

View file

@ -53,10 +53,10 @@ jobs:
with: with:
appID: ${{ secrets.RELEASE_APP_ID }} appID: ${{ secrets.RELEASE_APP_ID }}
appPrivateKey: ${{ secrets.RELEASE_APP_PK }} appPrivateKey: ${{ secrets.RELEASE_APP_PK }}
# neoforge:Geyser-NeoForge.jar // TODO 1.20.5
files: | files: |
bungeecord:Geyser-BungeeCord.jar bungeecord:Geyser-BungeeCord.jar
fabric:Geyser-Fabric.jar fabric:Geyser-Fabric.jar
neoforge:Geyser-NeoForge.jar
spigot:Geyser-Spigot.jar spigot:Geyser-Spigot.jar
standalone:Geyser-Standalone.jar standalone:Geyser-Standalone.jar
velocity:Geyser-Velocity.jar velocity:Geyser-Velocity.jar

View file

@ -1,5 +1,6 @@
architectury { architectury {
common("neoforge", "fabric") common("fabric")
//common("neoforge", "fabric") // todo 1.20.5
} }
loom { loom {

View file

@ -23,9 +23,8 @@
"geyser.mixins.json" "geyser.mixins.json"
], ],
"depends": { "depends": {
"fabricloader": ">=0.15.2", "fabricloader": ">=0.15.10",
"fabric": "*", "fabric": "*",
"minecraft": ">=1.20.4", "minecraft": ">=1.20.4"
"fabric-permissions-api-v0": "*"
} }
} }

View file

@ -29,6 +29,7 @@ import lombok.AllArgsConstructor;
import net.kyori.adventure.text.Component; import net.kyori.adventure.text.Component;
import net.kyori.adventure.text.serializer.gson.GsonComponentSerializer; import net.kyori.adventure.text.serializer.gson.GsonComponentSerializer;
import net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer; import net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer;
import net.minecraft.core.RegistryAccess;
import net.minecraft.network.Connection; import net.minecraft.network.Connection;
import net.minecraft.network.PacketSendListener; import net.minecraft.network.PacketSendListener;
import net.minecraft.network.protocol.Packet; import net.minecraft.network.protocol.Packet;
@ -69,7 +70,7 @@ public class ModPingPassthrough implements IGeyserPingPassthrough {
StatusInterceptor connection = new StatusInterceptor(); StatusInterceptor connection = new StatusInterceptor();
ServerStatusPacketListener statusPacketListener = new ServerStatusPacketListenerImpl(status, connection); ServerStatusPacketListener statusPacketListener = new ServerStatusPacketListenerImpl(status, connection);
statusPacketListener.handleStatusRequest(new ServerboundStatusRequestPacket()); statusPacketListener.handleStatusRequest(ServerboundStatusRequestPacket.INSTANCE);
// mods like MiniMOTD (that inject into the above method) have now processed the response // mods like MiniMOTD (that inject into the above method) have now processed the response
status = Objects.requireNonNull(connection.status, "status response"); status = Objects.requireNonNull(connection.status, "status response");
} catch (Exception e) { } catch (Exception e) {
@ -79,7 +80,7 @@ public class ModPingPassthrough implements IGeyserPingPassthrough {
} }
} }
String jsonDescription = net.minecraft.network.chat.Component.Serializer.toJson(status.description()); String jsonDescription = net.minecraft.network.chat.Component.Serializer.toJson(status.description(), RegistryAccess.EMPTY);
String legacyDescription = LEGACY_SERIALIZER.serialize(GSON_SERIALIZER.deserializeOr(jsonDescription, Component.empty())); String legacyDescription = LEGACY_SERIALIZER.serialize(GSON_SERIALIZER.deserializeOr(jsonDescription, Component.empty()));
return new GeyserPingInfo( return new GeyserPingInfo(

View file

@ -27,6 +27,7 @@ package org.geysermc.geyser.platform.mod.command;
import net.kyori.adventure.text.serializer.gson.GsonComponentSerializer; import net.kyori.adventure.text.serializer.gson.GsonComponentSerializer;
import net.minecraft.commands.CommandSourceStack; import net.minecraft.commands.CommandSourceStack;
import net.minecraft.core.RegistryAccess;
import net.minecraft.network.chat.Component; import net.minecraft.network.chat.Component;
import net.minecraft.server.level.ServerPlayer; import net.minecraft.server.level.ServerPlayer;
import org.checkerframework.checker.nullness.qual.NonNull; import org.checkerframework.checker.nullness.qual.NonNull;
@ -63,7 +64,7 @@ public class ModCommandSender implements GeyserCommandSource {
public void sendMessage(net.kyori.adventure.text.Component message) { public void sendMessage(net.kyori.adventure.text.Component message) {
if (source.getEntity() instanceof ServerPlayer player) { if (source.getEntity() instanceof ServerPlayer player) {
String decoded = GsonComponentSerializer.gson().serialize(message); String decoded = GsonComponentSerializer.gson().serialize(message);
player.displayClientMessage(Objects.requireNonNull(Component.Serializer.fromJson(decoded)), false); player.displayClientMessage(Objects.requireNonNull(Component.Serializer.fromJson(decoded, RegistryAccess.EMPTY)), false);
return; return;
} }
GeyserCommandSource.super.sendMessage(message); GeyserCommandSource.super.sendMessage(message);

View file

@ -27,37 +27,28 @@ package org.geysermc.geyser.platform.mod.world;
import com.github.steveice10.mc.protocol.data.game.entity.player.GameMode; import com.github.steveice10.mc.protocol.data.game.entity.player.GameMode;
import com.github.steveice10.mc.protocol.data.game.level.block.BlockEntityInfo; import com.github.steveice10.mc.protocol.data.game.level.block.BlockEntityInfo;
import net.kyori.adventure.text.serializer.gson.GsonComponentSerializer;
import net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer;
import net.minecraft.SharedConstants; import net.minecraft.SharedConstants;
import net.minecraft.core.BlockPos; import net.minecraft.core.BlockPos;
import net.minecraft.nbt.ByteArrayTag; import net.minecraft.core.RegistryAccess;
import net.minecraft.nbt.ByteTag; import net.minecraft.core.component.DataComponents;
import net.minecraft.nbt.CompoundTag; import net.minecraft.network.chat.Component;
import net.minecraft.nbt.DoubleTag;
import net.minecraft.nbt.EndTag;
import net.minecraft.nbt.FloatTag;
import net.minecraft.nbt.IntArrayTag;
import net.minecraft.nbt.IntTag;
import net.minecraft.nbt.ListTag;
import net.minecraft.nbt.LongArrayTag;
import net.minecraft.nbt.LongTag;
import net.minecraft.nbt.ShortTag;
import net.minecraft.nbt.StringTag;
import net.minecraft.nbt.Tag;
import net.minecraft.nbt.TagVisitor;
import net.minecraft.server.MinecraftServer; import net.minecraft.server.MinecraftServer;
import net.minecraft.server.level.ServerPlayer; import net.minecraft.server.level.ServerPlayer;
import net.minecraft.server.network.Filterable;
import net.minecraft.world.item.ItemStack; import net.minecraft.world.item.ItemStack;
import net.minecraft.world.item.WritableBookItem; import net.minecraft.world.item.component.WritableBookContent;
import net.minecraft.world.item.WrittenBookItem; import net.minecraft.world.item.component.WrittenBookContent;
import net.minecraft.world.level.Level; import net.minecraft.world.level.Level;
import net.minecraft.world.level.block.Block; import net.minecraft.world.level.block.Block;
import net.minecraft.world.level.block.entity.BannerBlockEntity; import net.minecraft.world.level.block.entity.BannerBlockEntity;
import net.minecraft.world.level.block.entity.BlockEntity; import net.minecraft.world.level.block.entity.BlockEntity;
import net.minecraft.world.level.block.entity.LecternBlockEntity; import net.minecraft.world.level.block.entity.LecternBlockEntity;
import net.minecraft.world.level.chunk.ChunkAccess; import net.minecraft.world.level.chunk.ChunkAccess;
import net.minecraft.world.level.chunk.ChunkStatus;
import net.minecraft.world.level.chunk.LevelChunk; import net.minecraft.world.level.chunk.LevelChunk;
import net.minecraft.world.level.chunk.LevelChunkSection; import net.minecraft.world.level.chunk.LevelChunkSection;
import net.minecraft.world.level.chunk.status.ChunkStatus;
import org.checkerframework.checker.nullness.qual.NonNull; import org.checkerframework.checker.nullness.qual.NonNull;
import org.cloudburstmc.math.vector.Vector3i; import org.cloudburstmc.math.vector.Vector3i;
import org.cloudburstmc.nbt.NbtMap; import org.cloudburstmc.nbt.NbtMap;
@ -72,10 +63,12 @@ import org.geysermc.geyser.util.BlockEntityUtils;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import java.util.Objects;
import java.util.concurrent.CompletableFuture; import java.util.concurrent.CompletableFuture;
public class GeyserModWorldManager extends GeyserWorldManager { public class GeyserModWorldManager extends GeyserWorldManager {
private static final GsonComponentSerializer GSON_SERIALIZER = GsonComponentSerializer.gson();
private static final LegacyComponentSerializer LEGACY_SERIALIZER = LegacyComponentSerializer.legacySection();
private final MinecraftServer server; private final MinecraftServer server;
public GeyserModWorldManager(MinecraftServer server) { public GeyserModWorldManager(MinecraftServer server) {
@ -180,7 +173,7 @@ public class GeyserModWorldManager extends GeyserWorldManager {
} }
ItemStack book = lectern.getBook(); ItemStack book = lectern.getBook();
int pageCount = WrittenBookItem.getPageCount(book); int pageCount = getPageCount(book);
boolean hasBookPages = pageCount > 0; boolean hasBookPages = pageCount > 0;
NbtMapBuilder lecternTag = LecternUtils.getBaseLecternTag(x, y, z, hasBookPages ? pageCount : 1); NbtMapBuilder lecternTag = LecternUtils.getBaseLecternTag(x, y, z, hasBookPages ? pageCount : 1);
lecternTag.putInt("page", lectern.getPage() / 2); lecternTag.putInt("page", lectern.getPage() / 2);
@ -189,11 +182,9 @@ public class GeyserModWorldManager extends GeyserWorldManager {
.putShort("Damage", (short) 0) .putShort("Damage", (short) 0)
.putString("Name", "minecraft:writable_book"); .putString("Name", "minecraft:writable_book");
List<NbtMap> pages = new ArrayList<>(hasBookPages ? pageCount : 1); List<NbtMap> pages = new ArrayList<>(hasBookPages ? pageCount : 1);
if (hasBookPages && WritableBookItem.makeSureTagIsValid(book.getTag())) { if (hasBookPages) {
ListTag listTag = book.getTag().getList("pages", 8); List<String> bookPages = getPages(book);
for (String page : bookPages) {
for (int i = 0; i < listTag.size(); i++) {
String page = listTag.getString(i);
NbtMapBuilder pageBuilder = NbtMap.builder() NbtMapBuilder pageBuilder = NbtMap.builder()
.putString("photoname", "") .putString("photoname", "")
.putString("text", page); .putString("text", page);
@ -243,9 +234,8 @@ public class GeyserModWorldManager extends GeyserWorldManager {
// Potentially exposes other NBT data? But we need to get the NBT data for the banner patterns *and* // Potentially exposes other NBT data? But we need to get the NBT data for the banner patterns *and*
// the banner might have a custom name, both of which a Java client knows and caches // the banner might have a custom name, both of which a Java client knows and caches
ItemStack itemStack = banner.getItem(); ItemStack itemStack = banner.getItem();
var tag = OpenNbtTagVisitor.convert("", itemStack.getOrCreateTag());
future.complete(tag); future.complete(null); // todo 1.20.5
return; return;
} }
future.complete(null); future.complete(null);
@ -257,95 +247,32 @@ public class GeyserModWorldManager extends GeyserWorldManager {
return server.getPlayerList().getPlayer(session.getPlayerEntity().getUuid()); return server.getPlayerList().getPlayer(session.getPlayerEntity().getUuid());
} }
// Future considerations: option to clone; would affect arrays private static int getPageCount(ItemStack itemStack) {
private static class OpenNbtTagVisitor implements TagVisitor { WrittenBookContent writtenBookContent = itemStack.get(DataComponents.WRITTEN_BOOK_CONTENT);
private String currentKey; if (writtenBookContent != null) {
private final com.github.steveice10.opennbt.tag.builtin.CompoundTag root; return writtenBookContent.pages().size();
private com.github.steveice10.opennbt.tag.builtin.Tag currentTag; } else {
WritableBookContent writableBookContent = itemStack.get(DataComponents.WRITABLE_BOOK_CONTENT);
OpenNbtTagVisitor(String key) { return writableBookContent != null ? writableBookContent.pages().size() : 0;
root = new com.github.steveice10.opennbt.tag.builtin.CompoundTag(key);
} }
}
@Override private static List<String> getPages(ItemStack itemStack) {
public void visitString(StringTag stringTag) { WrittenBookContent writtenBookContent = itemStack.get(DataComponents.WRITTEN_BOOK_CONTENT);
currentTag = new com.github.steveice10.opennbt.tag.builtin.StringTag(currentKey, stringTag.getAsString()); if (writtenBookContent != null) {
} return writtenBookContent.pages().stream()
.map(Filterable::raw)
@Override .map((component) -> Component.Serializer.toJson(component, RegistryAccess.EMPTY))
public void visitByte(ByteTag byteTag) { .map((json -> LEGACY_SERIALIZER.serialize(GSON_SERIALIZER.deserializeOr(json, net.kyori.adventure.text.Component.empty()))))
currentTag = new com.github.steveice10.opennbt.tag.builtin.ByteTag(currentKey, byteTag.getAsByte()); .toList();
} } else {
WritableBookContent writableBookContent = itemStack.get(DataComponents.WRITABLE_BOOK_CONTENT);
@Override if (writableBookContent == null) {
public void visitShort(ShortTag shortTag) { return List.of();
currentTag = new com.github.steveice10.opennbt.tag.builtin.ShortTag(currentKey, shortTag.getAsShort());
}
@Override
public void visitInt(IntTag intTag) {
currentTag = new com.github.steveice10.opennbt.tag.builtin.IntTag(currentKey, intTag.getAsInt());
}
@Override
public void visitLong(LongTag longTag) {
currentTag = new com.github.steveice10.opennbt.tag.builtin.LongTag(currentKey, longTag.getAsLong());
}
@Override
public void visitFloat(FloatTag floatTag) {
currentTag = new com.github.steveice10.opennbt.tag.builtin.FloatTag(currentKey, floatTag.getAsFloat());
}
@Override
public void visitDouble(DoubleTag doubleTag) {
currentTag = new com.github.steveice10.opennbt.tag.builtin.DoubleTag(currentKey, doubleTag.getAsDouble());
}
@Override
public void visitByteArray(ByteArrayTag byteArrayTag) {
currentTag = new com.github.steveice10.opennbt.tag.builtin.ByteArrayTag(currentKey, byteArrayTag.getAsByteArray());
}
@Override
public void visitIntArray(IntArrayTag intArrayTag) {
currentTag = new com.github.steveice10.opennbt.tag.builtin.IntArrayTag(currentKey, intArrayTag.getAsIntArray());
}
@Override
public void visitLongArray(LongArrayTag longArrayTag) {
currentTag = new com.github.steveice10.opennbt.tag.builtin.LongArrayTag(currentKey, longArrayTag.getAsLongArray());
}
@Override
public void visitList(ListTag listTag) {
var newList = new com.github.steveice10.opennbt.tag.builtin.ListTag(currentKey);
for (Tag tag : listTag) {
currentKey = "";
tag.accept(this);
newList.add(currentTag);
} }
currentTag = newList; return writableBookContent.pages().stream()
} .map(Filterable::raw)
.toList();
@Override
public void visitCompound(@NonNull CompoundTag compoundTag) {
currentTag = convert(currentKey, compoundTag);
}
private static com.github.steveice10.opennbt.tag.builtin.CompoundTag convert(String name, CompoundTag compoundTag) {
OpenNbtTagVisitor visitor = new OpenNbtTagVisitor(name);
for (String key : compoundTag.getAllKeys()) {
visitor.currentKey = key;
Tag tag = Objects.requireNonNull(compoundTag.get(key));
tag.accept(visitor);
visitor.root.put(visitor.currentTag);
}
return visitor.root;
}
@Override
public void visitEnd(@NonNull EndTag endTag) {
} }
} }
} }

View file

@ -46,6 +46,12 @@ loom {
silentMojangMappingsLicense() silentMojangMappingsLicense()
} }
indra {
javaVersions {
target(21)
}
}
configurations { configurations {
create("includeTransitive").isTransitive = true create("includeTransitive").isTransitive = true
} }
@ -104,7 +110,7 @@ afterEvaluate {
} }
dependencies { dependencies {
minecraft("com.mojang:minecraft:1.20.4") minecraft("com.mojang:minecraft:1.20.5-rc3")
mappings(loom.officialMojangMappings()) mappings(loom.officialMojangMappings())
} }
@ -128,6 +134,6 @@ modrinth {
syncBodyFrom.set(rootProject.file("README.md").readText()) syncBodyFrom.set(rootProject.file("README.md").readText())
uploadFile.set(tasks.getByPath("remapModrinthJar")) uploadFile.set(tasks.getByPath("remapModrinthJar"))
gameVersions.addAll("1.20.4") gameVersions.addAll("1.20.5")
failSilently.set(true) failSilently.set(true)
} }

View file

@ -22,7 +22,7 @@ val basePlatforms = setOf(
val moddedPlatforms = setOf( val moddedPlatforms = setOf(
projects.fabric, projects.fabric,
projects.neoforge, //projects.neoforge, // todo 1.20.5
projects.mod projects.mod
).map { it.dependencyProject } ).map { it.dependencyProject }

View file

@ -26,10 +26,11 @@
package org.geysermc.geyser.translator.inventory; package org.geysermc.geyser.translator.inventory;
import com.github.steveice10.mc.protocol.data.game.inventory.ContainerType; import com.github.steveice10.mc.protocol.data.game.inventory.ContainerType;
import com.github.steveice10.mc.protocol.data.game.item.component.DataComponentType;
import com.github.steveice10.mc.protocol.data.game.item.component.WritableBookContent;
import com.github.steveice10.mc.protocol.data.game.item.component.WrittenBookContent;
import com.github.steveice10.mc.protocol.packet.ingame.serverbound.inventory.ServerboundContainerButtonClickPacket; import com.github.steveice10.mc.protocol.packet.ingame.serverbound.inventory.ServerboundContainerButtonClickPacket;
import com.github.steveice10.mc.protocol.packet.ingame.serverbound.inventory.ServerboundContainerClosePacket; import com.github.steveice10.mc.protocol.packet.ingame.serverbound.inventory.ServerboundContainerClosePacket;
import com.github.steveice10.opennbt.tag.builtin.CompoundTag;
import com.github.steveice10.opennbt.tag.builtin.ListTag;
import org.cloudburstmc.math.vector.Vector3i; 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;
@ -152,7 +153,6 @@ public class LecternInventoryTranslator extends AbstractBlockInventoryTranslator
session.setDroppingLecternBook(false); session.setDroppingLecternBook(false);
InventoryUtils.closeInventory(session, inventory.getJavaId(), false); InventoryUtils.closeInventory(session, inventory.getJavaId(), false);
} else if (lecternContainer.getBlockEntityTag() == null) { } else if (lecternContainer.getBlockEntityTag() == null) {
CompoundTag tag = book.getNbt();
Vector3i position = lecternContainer.isUsingRealBlock() ? session.getLastInteractionBlockPosition() : inventory.getHolderPosition(); Vector3i position = lecternContainer.isUsingRealBlock() ? session.getLastInteractionBlockPosition() : inventory.getHolderPosition();
// If shouldExpectLecternHandled returns true, this is already handled for us // If shouldExpectLecternHandled returns true, this is already handled for us
@ -163,10 +163,20 @@ public class LecternInventoryTranslator extends AbstractBlockInventoryTranslator
&& !GameProtocol.is1_20_60orHigher(session.getUpstream().getProtocolVersion()); && !GameProtocol.is1_20_60orHigher(session.getUpstream().getProtocolVersion());
NbtMap blockEntityTag; NbtMap blockEntityTag;
if (tag != null) { if (book.getComponents() != null) {
int pagesSize = ((ListTag) tag.get("pages")).size(); int pages = 0;
WrittenBookContent writtenBookComponents = book.getComponents().get(DataComponentType.WRITTEN_BOOK_CONTENT);
if (writtenBookComponents != null) {
pages = writtenBookComponents.getPages().size();
} else {
WritableBookContent writableBookComponents = book.getComponents().get(DataComponentType.WRITABLE_BOOK_CONTENT);
if (writableBookComponents != null) {
pages = writableBookComponents.getPages().size();
}
}
ItemData itemData = book.getItemData(session); ItemData itemData = book.getItemData(session);
NbtMapBuilder lecternTag = LecternUtils.getBaseLecternTag(position.getX(), position.getY(), position.getZ(), pagesSize); NbtMapBuilder lecternTag = LecternUtils.getBaseLecternTag(position.getX(), position.getY(), position.getZ(), pages);
lecternTag.putCompound("book", NbtMap.builder() lecternTag.putCompound("book", NbtMap.builder()
.putByte("Count", (byte) itemData.getCount()) .putByte("Count", (byte) itemData.getCount())
.putShort("Damage", (short) 0) .putShort("Damage", (short) 0)

View file

@ -26,7 +26,6 @@
package org.geysermc.geyser.translator.protocol.java.level; package org.geysermc.geyser.translator.protocol.java.level;
import com.github.steveice10.mc.protocol.packet.ingame.clientbound.level.ClientboundBlockDestructionPacket; import com.github.steveice10.mc.protocol.packet.ingame.clientbound.level.ClientboundBlockDestructionPacket;
import com.github.steveice10.opennbt.tag.builtin.CompoundTag;
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.registry.BlockRegistries; import org.geysermc.geyser.registry.BlockRegistries;
@ -43,7 +42,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, new CompoundTag(""), false) * 20)); int breakTime = (int) (65535 / Math.ceil(BlockUtils.getBreakTime(session, BlockRegistries.JAVA_BLOCKS.getOrDefault(state, BlockMapping.DEFAULT), 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);

View file

@ -25,11 +25,12 @@
package org.geysermc.geyser.util; package org.geysermc.geyser.util;
import com.github.steveice10.opennbt.tag.builtin.CompoundTag; import com.github.steveice10.mc.protocol.data.game.item.component.DataComponents;
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.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.level.block.BlockStateValues; import org.geysermc.geyser.level.block.BlockStateValues;
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;
@ -40,28 +41,23 @@ import org.geysermc.geyser.translator.collision.BlockCollision;
public final class BlockUtils { public final class BlockUtils {
private static boolean correctTool(GeyserSession session, BlockMapping blockMapping, String itemToolType) { private static boolean correctTool(GeyserSession session, BlockMapping blockMapping, String itemToolType) {
switch (itemToolType) { return switch (itemToolType) {
case "axe": case "axe" -> session.getTagCache().isAxeEffective(blockMapping);
return session.getTagCache().isAxeEffective(blockMapping); case "hoe" -> session.getTagCache().isHoeEffective(blockMapping);
case "hoe": case "pickaxe" -> session.getTagCache().isPickaxeEffective(blockMapping);
return session.getTagCache().isHoeEffective(blockMapping); case "shears" -> session.getTagCache().isShearsEffective(blockMapping);
case "pickaxe": case "shovel" -> session.getTagCache().isShovelEffective(blockMapping);
return session.getTagCache().isPickaxeEffective(blockMapping); case "sword" -> blockMapping.getJavaBlockId() == BlockStateValues.JAVA_COBWEB_ID;
case "shears": default -> {
return session.getTagCache().isShearsEffective(blockMapping);
case "shovel":
return session.getTagCache().isShovelEffective(blockMapping);
case "sword":
return blockMapping.getJavaBlockId() == BlockStateValues.JAVA_COBWEB_ID;
default:
session.getGeyser().getLogger().warning("Unknown tool type: " + itemToolType); session.getGeyser().getLogger().warning("Unknown tool type: " + itemToolType);
return false; yield false;
} }
};
} }
private static double toolBreakTimeBonus(String toolType, String toolTier, boolean isShearsEffective) { private static double toolBreakTimeBonus(String toolType, String toolTier, boolean isShearsEffective) {
if (toolType.equals("shears")) return isShearsEffective ? 5.0 : 15.0; if (toolType.equals("shears")) return isShearsEffective ? 5.0 : 15.0;
if (toolType.equals("")) return 1.0; if (toolType.isEmpty()) return 1.0;
return switch (toolTier) { return switch (toolTier) {
// https://minecraft.wiki/w/Breaking#Speed // https://minecraft.wiki/w/Breaking#Speed
case "wooden" -> 2.0; case "wooden" -> 2.0;
@ -134,7 +130,7 @@ public final class BlockUtils {
return 1.0 / speed; return 1.0 / speed;
} }
public static double getBreakTime(GeyserSession session, BlockMapping blockMapping, ItemMapping item, @Nullable CompoundTag nbtData, boolean isSessionPlayer) { public static double getBreakTime(GeyserSession session, BlockMapping blockMapping, ItemMapping item, @Nullable DataComponents components, boolean isSessionPlayer) {
boolean isShearsEffective = session.getTagCache().isShearsEffective(blockMapping); //TODO called twice boolean isShearsEffective = session.getTagCache().isShearsEffective(blockMapping); //TODO called twice
boolean canHarvestWithHand = blockMapping.isCanBreakWithHand(); boolean canHarvestWithHand = blockMapping.isCanBreakWithHand();
String toolType = ""; String toolType = "";
@ -147,7 +143,8 @@ public final class BlockUtils {
correctTool = correctTool(session, blockMapping, toolType); correctTool = correctTool(session, blockMapping, toolType);
toolCanBreak = canToolTierBreakBlock(session, blockMapping, toolTier); toolCanBreak = canToolTierBreakBlock(session, blockMapping, toolTier);
} }
int toolEfficiencyLevel = ItemUtils.getEnchantmentLevel(nbtData, "minecraft:efficiency");
int toolEfficiencyLevel = ItemUtils.getEnchantmentLevel(components, Enchantment.JavaEnchantment.EFFICIENCY.ordinal());
int hasteLevel = 0; int hasteLevel = 0;
int miningFatigueLevel = 0; int miningFatigueLevel = 0;
@ -162,7 +159,7 @@ public final class BlockUtils {
boolean waterInEyes = session.getCollisionManager().isWaterInEyes(); boolean waterInEyes = session.getCollisionManager().isWaterInEyes();
boolean insideOfWaterWithoutAquaAffinity = waterInEyes && boolean insideOfWaterWithoutAquaAffinity = waterInEyes &&
ItemUtils.getEnchantmentLevel(session.getPlayerInventory().getItem(5).getNbt(), "minecraft:aqua_affinity") < 1; ItemUtils.getEnchantmentLevel(session.getPlayerInventory().getItem(5).getComponents(), Enchantment.JavaEnchantment.AQUA_AFFINITY.ordinal()) < 1;
return calculateBreakTime(blockMapping.getHardness(), toolTier, canHarvestWithHand, correctTool, toolCanBreak, toolType, isShearsEffective, return calculateBreakTime(blockMapping.getHardness(), toolTier, canHarvestWithHand, correctTool, toolCanBreak, toolType, isShearsEffective,
toolEfficiencyLevel, hasteLevel, miningFatigueLevel, insideOfWaterWithoutAquaAffinity, session.getPlayerEntity().isOnGround()); toolEfficiencyLevel, hasteLevel, miningFatigueLevel, insideOfWaterWithoutAquaAffinity, session.getPlayerEntity().isOnGround());
@ -172,12 +169,12 @@ public final class BlockUtils {
PlayerInventory inventory = session.getPlayerInventory(); PlayerInventory inventory = session.getPlayerInventory();
GeyserItemStack item = inventory.getItemInHand(); GeyserItemStack item = inventory.getItemInHand();
ItemMapping mapping = ItemMapping.AIR; ItemMapping mapping = ItemMapping.AIR;
CompoundTag nbtData = null; DataComponents components = null;
if (item != null) { if (item != null) {
mapping = item.getMapping(session); mapping = item.getMapping(session);
nbtData = item.getNbt(); components = item.getComponents();
} }
return getBreakTime(session, blockMapping, mapping, nbtData, true); return getBreakTime(session, blockMapping, mapping, components, true);
} }
/** /**

View file

@ -27,10 +27,7 @@ package org.geysermc.geyser.util;
import com.github.steveice10.mc.protocol.data.game.item.component.DataComponentType; import com.github.steveice10.mc.protocol.data.game.item.component.DataComponentType;
import com.github.steveice10.mc.protocol.data.game.item.component.DataComponents; import com.github.steveice10.mc.protocol.data.game.item.component.DataComponents;
import com.github.steveice10.opennbt.tag.builtin.CompoundTag; import com.github.steveice10.mc.protocol.data.game.item.component.ItemEnchantments;
import com.github.steveice10.opennbt.tag.builtin.ListTag;
import com.github.steveice10.opennbt.tag.builtin.StringTag;
import com.github.steveice10.opennbt.tag.builtin.Tag;
import net.kyori.adventure.text.Component; import net.kyori.adventure.text.Component;
import org.checkerframework.checker.nullness.qual.Nullable; import org.checkerframework.checker.nullness.qual.Nullable;
import org.geysermc.geyser.item.Items; import org.geysermc.geyser.item.Items;
@ -39,24 +36,17 @@ import org.geysermc.geyser.item.type.Item;
public class ItemUtils { public class ItemUtils {
public static int getEnchantmentLevel(@Nullable CompoundTag itemNBTData, String enchantmentId) { public static int getEnchantmentLevel(@Nullable DataComponents components, int enchantmentId) {
if (itemNBTData == null) { if (components == null) {
return 0; return 0;
} }
ListTag enchantments = itemNBTData.get("Enchantments");
if (enchantments != null) { ItemEnchantments enchantmentData = components.get(DataComponentType.ENCHANTMENTS);
for (Tag tag : enchantments) { if (enchantmentData == null) {
CompoundTag enchantment = (CompoundTag) tag; return 0;
StringTag enchantId = enchantment.get("id");
if (enchantId.getValue().equals(enchantmentId)) {
Tag lvl = enchantment.get("lvl");
if (lvl != null && lvl.getValue() instanceof Number number) {
return number.intValue();
}
}
}
} }
return 0;
return enchantmentData.getEnchantments().getOrDefault(enchantmentId, 0);
} }
/** /**

View file

@ -66,7 +66,7 @@ include(":ap")
include(":api") include(":api")
include(":bungeecord") include(":bungeecord")
include(":fabric") include(":fabric")
include(":neoforge") //include(":neoforge") // todo 1.20.5
include(":mod") include(":mod")
include(":spigot") include(":spigot")
include(":standalone") include(":standalone")
@ -78,7 +78,7 @@ include(":core")
// Specify project dirs // Specify project dirs
project(":bungeecord").projectDir = file("bootstrap/bungeecord") project(":bungeecord").projectDir = file("bootstrap/bungeecord")
project(":fabric").projectDir = file("bootstrap/mod/fabric") project(":fabric").projectDir = file("bootstrap/mod/fabric")
project(":neoforge").projectDir = file("bootstrap/mod/neoforge") //project(":neoforge").projectDir = file("bootstrap/mod/neoforge") // todo 1.20.5
project(":mod").projectDir = file("bootstrap/mod") project(":mod").projectDir = file("bootstrap/mod")
project(":spigot").projectDir = file("bootstrap/spigot") project(":spigot").projectDir = file("bootstrap/spigot")
project(":standalone").projectDir = file("bootstrap/standalone") project(":standalone").projectDir = file("bootstrap/standalone")